Data Shield
Tokenise PII before content reaches an LLM.
Status: Limited GA (v0.5). Data Shield tokenises 8 structured PII types (L1, regex + format validation) across 3 LLM entry points. Free-text names/locations/orgs, RAG chat, file contents, and a customer-held key are not in v0.5 — they ship in v1.0+. Read Limitations (v0.5) before relying on it for a compliance attestation.
What it is
Data Shield tokenises PII before a workflow, agent, or extraction call reaches the underlying
LLM provider. The LLM sees opaque tokens (EMAIL_84d0a133, SSN_c95eb795); the caller sees the
original values restored in the response. Every event is recorded in an immutable audit log with
entity counts per type — never raw values.
Tokenisation is deterministic within a request scope and isolated across scopes:
- Within one call the same raw value always maps to the same token, so the LLM reasons about "the customer" coherently across messages in that call.
- Across calls (and across tenants) the same value maps to a different token — there is no
cross-call or cross-tenant token reuse. The scope key is
{tenant_id}:{scope_type}:{scope_id}, so tenant isolation holds by construction.
In v0.5 the scope is per-request and ephemeral — the token map lives in memory for the duration of one request and is destroyed when the request frame ends. There is no on-disk token map, and no customer-held key yet. Consistency across documents or sessions requires the v1.0 KMS-backed persistent scope (see roadmap).
When to use it
Turn it on for any LLM step that may see personal or sensitive data — extraction over identity documents, agents handling customer records, free-form LLM tasks on user content. It is a core governance control.
Data Shield is opt-in and off by default. Decide deliberately:
- Enable per node when one specific
llm_task/agent_tasktouches PII. - Require per workflow when every LLM node in a sensitive workflow must be shielded and you want the executor to fail the run if an author forgets. Use this for regulated workflows (insurance, legal, financial) where a single un-shielded node is a breach.
- Set per pack when a Solution Pack should ship the policy so every instantiated workflow inherits it.
How it works
Process flow — tokenise, call, restore:
Call flow — through the gateway:
Sub-features
- L1 detection across 8 entity types: EMAIL, PHONE, SSN, CREDIT_CARD, IP, AADHAAR, PAN, IBAN.
- Three opt-in scopes — per-node, per-workflow (require on every LLM node), per-pack (manifest policy).
- Audit log — counts by type, layers invoked, stage latencies, retention timestamp, correlation id; immutable after write.
- Kill switches — disable gateway or audit; tune retention.
- Recall-biased detectors — tuned to over-tokenise rather than miss (a false positive is restored on the return path; a false negative is a leak).
Configuration parameters
The three opt-in scopes
| Scope | Where you set it | Effect |
|---|---|---|
| Per-node | WorkflowBuilder → select an llm_task / agent_task → "Data Shield" card → flip the switch | Tokenises that node's LLM calls. Optionally restrict to a subset of the 8 types via the chip row. |
| Per-workflow | WorkflowBuilder → Resilience tab → "Data Shield policy" card → "Require Data Shield on every LLM node" | Executor fails any run whose LLM nodes haven't opted in (DATA_SHIELD_POLICY_VIOLATION). |
| Per-pack | data_shield_policy in the solution-pack manifest | Every workflow instantiated from the pack inherits the policy onto its activity row; authors can refine per-instance. |
Kill switches (operators only — off by default)
| Variable | Service | Effect |
|---|---|---|
DATA_SHIELD_DISABLED=true | llm-service | Bypass the gateway entirely — raw payload reaches the LLM, no audit row. Incident response only. |
DATA_SHIELD_AUDIT_DISABLED=true | llm-service | Tokenise normally, skip the audit emit. Use only if the audit DB is the bottleneck. |
DATA_SHIELD_AUDIT_RETENTION_DAYS=N | DMS | Override the default 30-day retention on new audit rows. |
Both kill switches are off in normal operation. Any period they are on is an attestation gap and must be logged in the operator runbook.
The 8 L1 entity types (always on when the shield is enabled)
| Type | Detection | Region |
|---|---|---|
EMAIL | RFC-5322 subset regex | International |
PHONE | E.164 + common US/UK/IN local formats | International |
SSN | US SSN; rejects 000 / 666 / 9xx prefixes | United States |
CREDIT_CARD | 12–19 digits + Luhn validation | International |
IP | IPv4 dotted quad | International |
AADHAAR | 12 digits + Verhoeff checksum | India |
PAN | 5 letters + 4 digits + letter | India |
IBAN | Basic IBAN structural check | International |
L1 latency target: under 5 ms per request at the 95th percentile.
Tips & best practices
- Require the policy on regulated workflows. Per-node opt-in is convenient but easy to forget; in insurance/legal/financial workflows set the Resilience-tab policy to required so a forgotten node fails the run loudly instead of leaking silently.
- Review the audit log regularly. End users see their own activity at
/account/activity; Super Admins search across tenants at/admin/audit. Use it to confirm the entity counts look right for each run (e.g. a customer-record agent should show non-zeroEMAIL/PHONE). Rows are immutable and contain counts only — there are no raw values to leak. - Don't treat tokenisation as a PII classifier. Detectors are recall-biased: a 9-digit string that resembles an SSN may be tokenised even if it isn't one. "We tokenised it" means "candidate PII", not "this is definitely PII".
- Know what v0.5 does NOT cover before signing anything: free-text names/locations/orgs,
RAG chat, the public chatbot, Prompt Lab previews, file (
file_urls) contents, multi-script / non-Latin PII, and any customer-held encryption key. See Limitations. - Tune retention to your obligations. The DS audit row default is 30 days — shorter than the
rest of the audit log. Set
DATA_SHIELD_AUDIT_RETENTION_DAYSto your record-keeping requirement.
Concrete examples
BEFORE / AFTER — what the provider sees vs. what the caller gets
The author sends a payload with PII. The provider only ever sees tokens; the caller gets the originals restored.
BEFORE (your payload)
"Email jane.doe@acme.com or call +1-415-555-0142. SSN 086-12-3456."
WHAT THE LLM PROVIDER SEES (tokenised)
"Email EMAIL_84d0a133 or call PHONE_1f9c2a07. SSN SSN_c95eb795."
AFTER (response restored to caller)
"I have emailed jane.doe@acme.com and noted SSN 086-12-3456 on file."Within this one call, jane.doe@acme.com always maps to EMAIL_84d0a133. In a different call
the same address would map to a different token.
Enabling it on a node and requiring it on the workflow
- WorkflowBuilder → select the
agent_tasknode → Data Shield card → flip the switch on. (Optional: in the chip row, restrict toEMAIL,PHONE,SSNonly.) - WorkflowBuilder → Resilience tab → Data Shield policy → "Require Data Shield on every LLM node."
- Any LLM node now left un-shielded makes the run terminate with
DATA_SHIELD_POLICY_VIOLATION.
For a pack, declare it in the manifest instead so every instantiated workflow inherits it:
# solution-pack manifest
data_shield_policy:
required: true
entity_types: [EMAIL, PHONE, SSN, AADHAAR, PAN]An audit-log entry (counts only — never raw values)
{
"action": "data_shield.tokenise",
"entity_counts": { "EMAIL": 1, "PHONE": 1, "SSN": 1 },
"layers": ["L1"],
"latencies_ms": { "tokenise_ms": 1, "roundtrip_ms": 1461 },
"retention_days": 30,
"correlation_id": "run_7af3c9e2",
"provider": "claude",
"model": "claude-opus-4-1"
}There is no field anywhere in this row that holds jane.doe@acme.com or the SSN — only the count
{ "SSN": 1 }.
Dependencies
- llm-service — hosts the tokenisation gateway and entry points (
/api/v1/chat,/api/v1/extract). - DMS — audit log storage and retention; user activity view at
/account/activity. - Workflow executor — enforces the per-workflow required policy.
Limitations (v0.5)
Data Shield v0.5 is deliberately narrow. The following are known gaps — read them before relying on it for a compliance attestation:
- Free-text PII is not detected. Names, locations, organisations, narrative dates
(PERSON / LOC / ORG) need L3 NER, which lands in v1.0.
"Alice Johnson visited the New York office"reaches the LLM intact in v0.5 — only the 8 L1 types are caught. - RAG chat is not tokenised. Questions and retrieved context on the Knowledge Base / RAG path go to the LLM unmodified (v1.0).
- Public chatbot and Prompt Lab previews are not covered — end-user messages and authored preview prompts reach the provider as-is.
- File contents are not tokenised.
file_urlsare sent to the multimodal provider as-is; in-boundary OCR + pre-LLM tokenisation is a v1.0 deliverable. - Multi-script / non-Latin PII (Cyrillic, Han, Arabic, etc.) is not specifically detected.
- Per-request scope only — no cross-call or cross-document persistence, and no customer-held key (both require the v1.0 KMS-backed scope).
Failure modes: detector error → fail-closed (HTTP 503); audit emit failure → fail-open; required-policy violation → workflow fails terminal; unknown token in the response → passed through untouched. See Troubleshooting.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| LLM call returns 503, run blocked | Detector errored at ingress (regex panic, unicode edge case). Data Shield is fail-closed — a missed PII check could be a breach, so it blocks rather than leak. | Retry; if it persists, capture the input shape and report it. As a last resort an operator can set DATA_SHIELD_DISABLED (incident only — logs an attestation gap). |
| Run succeeded but no audit row appeared | Audit emit failed (DMS down, JWT/network). Audit is fail-open — observability, not correctness — so the chat is preserved and a warning is logged. | Check the llm-service warning log and DMS health; the LLM call itself was correct and shielded. |
Workflow fails with DATA_SHIELD_POLICY_VIOLATION | The workflow requires Data Shield on every LLM node, but one node hasn't opted in. The executor enforces the author's declared contract. | Enable the Data Shield card on the flagged node, or relax the Resilience-tab requirement if the node genuinely needs no shield. |
| A token-shaped string appears in the final response | The model invented a string matching our token pattern; Data Shield does not own it, so it is passed through untouched to avoid false substitution. | Expected behaviour. If the model hallucinates tokens often, tighten the prompt. |
| Same value got a different token in another run / session | "Deterministic within request scope" — consistency holds only inside one request's ephemeral map. Across requests, sessions, and tenants the same value deliberately maps to a different token. | Expected in v0.5. Cross-call / cross-document consistency requires the v1.0 KMS-backed persistent scope. |
How to test
- Enable on a node. In WorkflowBuilder, select an
llm_task, open the Data Shield card, and flip the switch on. - Run with sample PII. Execute it over text containing an email and an SSN, e.g.
"Contact jane.doe@acme.com, SSN 086-12-3456." - Confirm tokens reached the LLM. Inspect the run / provider request and verify the payload
shows
EMAIL_*andSSN_*tokens — not the raw values. - Confirm values were restored. Verify the response handed back to the workflow contains the
original
jane.doe@acme.comand SSN. - Inspect the audit log. At
/account/activityconfirm onedata_shield.tokeniserow withentity_counts: { EMAIL: 1, SSN: 1 },layers: ["L1"], latencies, and a correlation id — and no raw values anywhere in the row. - Verify the required policy. Set the workflow's Resilience-tab policy to required, leave a
second LLM node opted out, run it, and confirm the run terminates with
DATA_SHIELD_POLICY_VIOLATION.
Cross-links & roadmap
Related pages
- Governance — Data Shield is one of the platform's core governance controls.
- Knowledge Base / RAG — note that RAG chat is NOT tokenised in v0.5; questions and retrieved context reach the LLM unmodified until v1.0.
Coming soon (forward-looking; not part of the v0.5 attestation):
| Capability | Target |
|---|---|
| RAG chat, public chatbot, and Prompt Lab path coverage | v0.6 / v1.0 |
| In-boundary OCR + file-content tokenisation | v1.0 |
| Customer-held KMS key (Google CMEK first) | v1.0 |
| Persistent document scope (cross-document consistency) | v1.0 |
| L2 gazetteer + L3 NER (free-text names/locations/orgs) | v1.0 |
| Hash-chained evidence-pack export (signed PDF + JSON) | v1.0 |
| L4 commercial detector, L5 local-LLM detector, sensitivity-based routing | v1.5 |
APIs used
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/chat | Direct LLM chat (shielded) |
POST | /api/v1/extract | Structured extraction (shielded) |
| (view) | /account/activity | User's own tokenisation activity |
| (view) | /admin/audit | Cross-tenant audit search (Super Admin) |
See the synced Data Shield reference and
architecture/data-shield/spec.md for the full spec.