Data Shield
Tokenise PII before content reaches an LLM.
Status: GA (v3.0). Data Shield tokenises 8 structured PII types (L1), tenant word lists (L2) and free-text names, locations and organisations (L3 NER, Microsoft Presidio), plus customer-authored detectors and three domain packs. RAG chat, the public chatbot, Prompt Lab, file contents, and a customer-held key are not in v3.0 — they ship in v3.5. Read Limitations 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. Data Shield records every event 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 v3.0 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 v3.5 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 node (
llm_task,agent_task, extraction / classification / summarization) touches 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.
- L2 gazetteer — tenant word lists (competitor names, product codes), case-insensitive, word-boundary matched.
- L3 NER (Microsoft Presidio) — free-text PERSON, LOCATION, ORGANIZATION and more;
DATE_TIMEis opt-in. - Custom detectors — tenant-scoped patterns, word lists and smart recognizers, added without a deploy.
- Detector packs — Insurance, HR and Financial essentials; one-click install / uninstall per tenant.
- Admin UIs —
/settings/data-shield(Simple wizard or Advanced tabs) and a live tokenisation demo at/data-shield/demo. - 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, extraction_task, classification_task, summarization_task or agent_task → Data Shield card → flip the switch | Tokenises that node's LLM calls. Optionally restrict to a subset of entity 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 | data-shield-gateway | 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 | Requires formatting (+ prefix, parens, or separators); bare 7-digit runs don't fire | 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. L3 (Presidio NER) also catches names, locations and organisations; L1 always wins an overlap.
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; operators search across tenants at/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 v3.0 does NOT cover before signing anything: RAG chat, the public chatbot,
Prompt Lab previews, file (
file_urls) contents, 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 and after: what the provider sees and 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 [email protected] 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 [email protected] and noted SSN 086-12-3456 on file."Within this one call, [email protected] always maps to EMAIL_84d0a133. In a different call
the same address would map to a different token.
Enable it on a node and require 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.
- Run the workflow. If any LLM node is left un-shielded, the run terminates 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 [email protected] or the SSN — only the count
{ "SSN": 1 }.
Dependencies
- llm-service — hosts the entry points (
/api/v1/chat,/api/v1/extract) and calls the gateway. - data-shield-gateway — internal-only service that runs detection, tokenisation and audit forwarding.
- DMS — audit log storage and retention, tenant detector storage; user activity view at
/account/activity. - Workflow executor — enforces the per-workflow required policy.
Limitations
The following are known gaps in v3.0 — read them before relying on it for a compliance attestation:
- RAG chat is not tokenised. Questions and retrieved context on the Knowledge Base / RAG path go to the LLM unmodified (v3.5).
- Public chatbot and Prompt Lab previews are not covered — end-user messages and authored preview prompts reach the provider as-is (v3.5).
- File contents are not scanned. With the shield on, a call that attaches
file_urlsis refused with HTTP 400 and a clear message — extract the text first and send it through the shield, or disable Data Shield for that workflow. In-boundary OCR is a v3.5 deliverable. - Phone formatting matters. A bare 7-digit string is left alone; add a custom pattern for unformatted phone shapes you actually see.
- NER uses a small English-only model by default — fast, but it occasionally misses; operators can
switch to the larger model (
DATA_SHIELD_SPACY_MODEL) for higher precision. - Per-request scope only — no cross-call or cross-document persistence, and no customer-held key (both require the v3.5 KMS-backed scope).
Failure modes: detector error or gateway unreachable → fail-closed (HTTP 503); shielded
call with file_urls → fail-fast (HTTP 400); 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 data-shield-gateway 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 the 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 v3.0. Cross-call / cross-document consistency requires the v3.5 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 [email protected], 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
[email protected]and 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 v3.0; questions and retrieved context reach the LLM unmodified until v3.5.
Coming soon (forward-looking; not part of the v3.0 attestation):
| Capability | Target |
|---|---|
| RAG chat, public chatbot, and Prompt Lab path coverage | v3.5 |
| In-boundary OCR + file-content tokenisation | v3.5 |
| Customer KMS vault | v3.5 |
| Persistent document scope (cross-document consistency) | v3.5 |
| Hash-chained evidence-pack export | v3.5 |
| L4 commercial detector, L5 local-LLM detector, sensitivity-based routing, image redaction | v4.0 |
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 |
POST | /api/data-shield/preview | Live tokenisation demo (DMS proxy) |
| (view) | /audit | Cross-tenant audit search (operators) |
See the synced Data Shield reference and
architecture/data-shield/spec.md for the full spec.