From 14a155aabcecb79a5fbdfd442a1d684ecb901fa4 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Mon, 13 Jul 2026 01:35:12 +0800 Subject: [PATCH] docs(privacy): record the OpenAI cross-border basis (PIA-1 APP 8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Capture the contractual cross-border basis for disclosing query text + retrieved excerpts to OpenAI (US) as a decision-ready record, closing the engineering side of PIA-1. The remaining DPA execution / ZDR application is an operator+legal step and is tracked with a fill-in status block. Key findings (verified 2026-07-13 against OpenAI's public docs): - the app's egress endpoints (/v1/responses store:false, /v1/embeddings) are ZDR-eligible — neither is on OpenAI's ZDR exclusion list; - OpenAI now offers Australia API data residency (storage at rest; inference still US/Europe/UAE) — an option that postdates the PIA; - recommended APP 8 path = APP 8.1 "reasonable steps" via executed DPA + ZDR (+ optional AU residency), not consent — flagged for counsel. APP 5/1 (the /privacy collection notice + composer reminder) is already live on main via #513; this only covers the outstanding APP 8 basis. Adds docs/openai-cross-border-basis.md and links it from the PIA-1 gap entry. Docs-only; code follow-ups (ZDR/residency wiring) are documented as decision-gated, not made here. Co-Authored-By: Claude Opus 4.8 --- docs/openai-cross-border-basis.md | 164 ++++++++++++++++++++++++++++++ docs/privacy-impact-assessment.md | 7 ++ 2 files changed, 171 insertions(+) create mode 100644 docs/openai-cross-border-basis.md diff --git a/docs/openai-cross-border-basis.md b/docs/openai-cross-border-basis.md new file mode 100644 index 000000000..af236ee6f --- /dev/null +++ b/docs/openai-cross-border-basis.md @@ -0,0 +1,164 @@ +# Cross-border disclosure basis — OpenAI (PIA-1) + +**Status:** Decision-ready — awaiting the operator/legal step · **Date:** 2026-07-13 +**Owner of the open step:** account holder for `OPENAI_API_KEY` + privacy adviser +**Closes:** the contractual half of **PIA-1** in [docs/privacy-impact-assessment.md](privacy-impact-assessment.md) §10. +**Companion:** the `/privacy` collection notice ([src/app/privacy/page.tsx](../src/app/privacy/page.tsx)) and composer reminder ([src/lib/ui-copy.ts](../src/lib/ui-copy.ts)) satisfy the APP 5 / APP 1 half. + +> **Not legal advice.** This records the current, verifiable facts about OpenAI's data-handling +> terms and maps them to APP 8 so a qualified privacy adviser can sign off the cross-border basis. +> The APP-8 reasoning below is an engineering interpretation and must be confirmed by counsel before +> real patient use. + +--- + +## 1. Why this exists + +The app's only cross-border flow is the query text + retrieved excerpts sent to OpenAI in the United +States for embedding and answer synthesis (PIA §3–4; verified still true in code — +[src/lib/openai.ts:75-79](../src/lib/openai.ts) builds a plain `new OpenAI({ apiKey, timeout, maxRetries })` +with no `baseURL`/ZDR header, `store:false` by default, and `prompt_cache_retention` forced to `"24h"` +for gpt-5.5 at [openai.ts:174](../src/lib/openai.ts)). + +Two obligations attach to that flow: + +- **APP 8 (cross-border disclosure).** Before disclosing personal information overseas the entity must + take **reasonable steps** to ensure the recipient handles it consistently with the APPs. Under + **s16C** of the _Privacy Act 1988_ (Cth) the discloser stays **accountable** for the overseas + recipient's acts unless an APP 8.2 exception applies. Health/mental-health data is _sensitive + information_ — the highest-protection category — so this is the launch-critical item. +- **APP 5 (notification).** Individuals must be told their information is disclosed overseas. + **Already shipped** in the `/privacy` page and composer notice (see §7). + +The code-side controls cannot _by themselves_ discharge APP 8 — the "reasonable steps" are largely +**contractual**. That contract is the open step this document tracks. + +## 2. What actually crosses the border + +| Egress | Payload | Endpoint | Reference | +| --------- | ---------------------------------------------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------------------- | +| Embedding | Raw query text (normalized) | `POST /v1/embeddings` (`text-embedding-3-small`) | [openai.ts embedText](../src/lib/openai.ts) | +| Answer | Raw query verbatim + retrieved chunk text + static system prompt | `POST /v1/responses` (`gpt-5.5`, `store:false`) | [rag.ts:4220](../src/lib/rag.ts) · [rag-source-block.ts:180](../src/lib/rag-source-block.ts) | + +The app **adds no patient identifiers** and stores queries only as a keyed hash locally; but it does +**not scrub** PHI a clinician types. Everything else (documents, embeddings, logs, auth) stays at rest +in **Sydney — AWS `ap-southeast-2`** (PIA §7). + +## 3. OpenAI's current terms (verified 2026-07-13) + +Facts pulled from OpenAI's public policy/docs pages on 2026-07-13. **Re-verify at execution time** — +these terms change; the PIA (2026-07-06) already predates the Australia data-residency option below. + +| Item | Current position | Source | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **DPA available** | OpenAI executes a Data Processing Addendum for API customers; OpenAI acts as **processor**, and binds each sub-processor to comparable obligations. Current version `v.010126` (1 Jan 2026). | [DPA](https://openai.com/policies/data-processing-addendum/) · [DPA PDF](https://cdn.openai.com/pdf/openai-data-processing-addendum.pdf) | +| **Training** | API inputs/outputs are **not used to train models** by default (API opt-out since 1 Mar 2023). | [Data controls](https://developers.openai.com/api/docs/guides/your-data) | +| **Default retention** | Inputs/outputs retained **up to 30 days** for abuse monitoring, then deleted. | [Data controls](https://developers.openai.com/api/docs/guides/your-data) | +| **Zero Data Retention (ZDR)** | Removes the 30-day abuse-monitoring retention; **not self-serve** — prior approval by OpenAI, configured per **project**. Apply via the account/sales team. | [Data controls](https://developers.openai.com/api/docs/guides/your-data) | +| **Data residency** | API data residency now covers **Australia** (among US, Europe, UK, Canada, Japan, Korea, Singapore, India, UAE). Enabled by creating a **new Project** and selecting the country; eligibility via sales. **Australia = storage at rest only** — regional _processing/inference_ is US/Europe/UAE only. ~10% uplift for models released from 5 Mar 2026. | [Data residency (API)](https://help.openai.com/en/articles/10503543-data-residency-for-the-openai-api) · [Announcement](https://openai.com/index/expanding-data-residency-access-to-business-customers-worldwide/) | +| **Sub-processors** | Published list of sub-processors that may process Customer Data. Review for the APP 8 accountability chain. | [Sub-processor list](https://openai.com/policies/sub-processor-list/) · [platform](https://platform.openai.com/subprocessors) | +| **Prompt caching** | For gpt-5.5, `prompt_cache_retention` cannot be `in_memory`; app forces `"24h"` ([openai.ts:174](../src/lib/openai.ts)). Whether ZDR also zeroes the prompt cache must be **confirmed in writing** (see §6, PIA-6). | [Data controls](https://developers.openai.com/api/docs/guides/your-data) | + +## 4. This app's endpoints are ZDR-eligible + +ZDR **excludes** stateful products: Conversations, Assistants/threads, ChatKit, `/v1/files`, vector +stores, fine-tuning, video, vision fine-tuning. This app uses **only** `/v1/responses` (stateless, +`store:false`) and `/v1/embeddings` — **neither is on the exclusion list**. So the two egress points +that carry PHI are exactly the ones ZDR is designed to cover. This is the strongest lever available. + +## 5. Recommended basis to satisfy APP 8 _(engineering interpretation — counsel to confirm)_ + +Relying on **APP 8.1 "reasonable steps"** (a binding contract that holds the recipient to +APP-comparable handling) is the mainstream, defensible path — **not** consent under APP 8.2(b), which +is fragile as a sole basis for sensitive health information. The "reasonable steps" package: + +1. **Executed OpenAI DPA** — the contractual spine (processor obligations, sub-processor flow-down, + security, breach notice, SCC-equivalent terms). **Required.** +2. **ZDR on the project** behind the production key — removes the 30-day retention for both egress + points (§4). **Strongly recommended.** +3. **Australia data residency** for storage at rest — keeps stored content onshore (inference still + crosses; PHI-minimisation reduces what inference sees). **Optional but high-value** for a WA + clinical posture; weigh against the ~10% cost uplift. +4. **No-training default** (already OpenAI's API default) — confirm in the executed contract. +5. **The app's own minimisation** as documented "reasonable steps" under APP 11: query hashing at + rest, `store:false`, Sydney residency, and the shipped PHI reminder (do-not-enter-identifiers). + +Items 1–2 (plus documenting 4–5) are what turn PIA-1 from open to closed. Item 3 strengthens it. + +## 6. Open question to pin with OpenAI + +**Does ZDR eliminate the forced 24h gpt-5.5 prompt cache**, or does an encrypted ≤24h cache persist +regardless? Get this in writing — it determines whether **PIA-6** is fully resolved by ZDR or merely +mitigated. Record the answer in the status block. + +## 7. Consistency with the shipped user-facing notice + +The `/privacy` page and composer notice already tell users: data is stored in **Sydney**; question +text + excerpts go to **OpenAI in the US** ("the only point where data leaves Australia"); OpenAI is +**asked not to retain** requests (`store:false`); retention is 30d/90d. This document must stay +consistent with those claims. + +- **Merge status:** the APP-5 half is **live on `main`** — `src/app/privacy/page.tsx` and the composer + notice landed via **PR #513** (`eeb2340ad`). So APP 5/1 is met; only the APP 8 contractual basis below + remains. +- **Follow-up:** if **Australia data residency** is enabled, the `/privacy` copy ("the only point where + data leaves Australia") stays accurate for _processing_, but the "where stored" section can be + strengthened to note US/AU storage — update copy if residency is adopted. + +## 8. Operator action checklist + +Actions **1–3 must be performed by the account holder** in OpenAI's dashboard/legal process — they +involve accepting agreements and changing account settings, which an automated agent must not do. + +- [ ] **1. Execute the OpenAI DPA** for the org behind the production `OPENAI_API_KEY` + → [openai.com/policies/data-processing-addendum](https://openai.com/policies/data-processing-addendum/). + Store the countersigned copy; record version + date below. +- [ ] **2. Apply for ZDR** on the production project via the OpenAI account/sales team. Confirm it + covers `/v1/responses` + `/v1/embeddings`. Record project id + approval date. +- [ ] **3. Decide on Australia data residency** (new Project + country selection; sales-gated). + Record region + date, or record an explicit decision not to adopt it and why. +- [ ] **4. Confirm the ZDR ↔ prompt-cache behaviour** in writing (§6); record the answer. +- [ ] **5. Review the sub-processor list** for anything counsel should note in the APP 8 chain. +- [ ] **6. Legal sign-off** that the §5 package satisfies APP 8 for sensitive health information. +- [ ] **7. Keep `/privacy` copy in sync** if AU residency is adopted (§7) — note US/AU storage. +- [ ] **8. Code follow-ups** once the above land (§9), if adopted. + +> APP 5/1 (the collection notice + `/privacy` page) is **already done** — live on `main` via PR #513. +> This checklist covers only the remaining **APP 8** contractual basis. + +### Status record — fill in as steps complete + +| Field | Value | Date | Evidence | +| ----------------------------------- | ------------------------- | ---- | -------- | +| OpenAI org / production project id | _tbd_ | | | +| DPA executed (version) | _no (v.010126 available)_ | | | +| ZDR approved (project) | _no_ | | | +| ZDR covers /responses + /embeddings | _tbd_ | | | +| ZDR zeroes prompt cache? (§6) | _tbd_ | | | +| Australia data residency | _not enabled_ | | | +| No-training confirmed in contract | _API default_ | | | +| Counsel sign-off (APP 8) | _pending_ | | | + +## 9. Code follow-ups triggered by the outcome + +These touch the OpenAI request path — do them **only after** the legal decision, and treat them as +provider-path changes (confirm before running against live). + +- **ZDR granted:** no code change strictly required (ZDR is account/project-side). Optionally revisit + the forced `"24h"` prompt-cache retention ([openai.ts:174](../src/lib/openai.ts)) depending on the §6 + answer, and note the resolution against **PIA-6**. +- **Australia data residency adopted:** the client currently has no `baseURL` override + ([openai.ts:75-79](../src/lib/openai.ts)). Data-residency Projects route via the standard API with a + region-scoped project key; confirm whether a `baseURL`/project-key change is needed and wire an + `OPENAI_BASE_URL` env only if OpenAI's residency setup requires it. +- **Defence-in-depth (optional, PIA-1 fix #4):** a lightweight outbound PHI/entity strip on the query + before egress. Larger change; not required to close PIA-1. + +## 10. Sources + +- OpenAI — [Data controls in the OpenAI platform](https://developers.openai.com/api/docs/guides/your-data) +- OpenAI — [Data Processing Addendum](https://openai.com/policies/data-processing-addendum/) · [PDF v.010126](https://cdn.openai.com/pdf/openai-data-processing-addendum.pdf) +- OpenAI — [Sub-processor list](https://openai.com/policies/sub-processor-list/) +- OpenAI — [Data residency for the OpenAI API](https://help.openai.com/en/articles/10503543-data-residency-for-the-openai-api) · [Expanding data residency worldwide](https://openai.com/index/expanding-data-residency-access-to-business-customers-worldwide/) +- OAIC — Australian Privacy Principles (APP 8 cross-border disclosure; s16C accountability), _Privacy Act 1988_ (Cth) +- Internal — [Privacy Impact Assessment](privacy-impact-assessment.md) (PIA-1, PIA-6) diff --git a/docs/privacy-impact-assessment.md b/docs/privacy-impact-assessment.md index fae5b515f..aa04b0c56 100644 --- a/docs/privacy-impact-assessment.md +++ b/docs/privacy-impact-assessment.md @@ -332,6 +332,13 @@ compliance-posture and PHI-minimisation gaps. `docs/`. (2) Add an APP-5 **collection/OpenAI-disclosure notice** at the query UI and in a privacy policy. (3) Consider an **on-query PHI reminder** ("do not enter identifiable patient details"). (4) Optionally, a lightweight PHI-scrub / entity-strip on the outbound query as defence-in-depth. +- **Progress (2026-07-13):** fixes (2)+(3) are **live on `main`** via PR #513 + ([src/app/privacy/page.tsx](src/app/privacy/page.tsx), composer notice) — so APP 5/1 is met. Fix (1), + the contractual basis, is captured decision-ready + in **[docs/openai-cross-border-basis.md](docs/openai-cross-border-basis.md)**, which also records that + the app's egress endpoints (`/v1/responses`, `/v1/embeddings`) are **ZDR-eligible** and that OpenAI now + offers **Australia data residency** (storage) — an option that postdates this PIA. The remaining step + (execute DPA / apply ZDR / counsel sign-off) is operator/legal, not code. ### PIA-2 — Query-hash HMAC silently downgrades without the secret **(High)**