Agent-Safe Reads (Read-Time Processing)
Keep raw data at rest. Let AI agents read only the safe projection — Maskura scrubs PII and encrypts on the way out, not on the way in.
The problem
Write-time processing is table stakes: your app PUTs through Maskura and PII is cleaned before storage. But agents often need to read existing datasets — buckets written by other systems, exports, or raw collections. Today the industry answer is a second cleaned copy, which drifts out of sync and doubles storage.
Maskura does the inverse: the object at rest stays raw. When an agent reads through Maskura with x-maskura-process: read, the WASM pipeline runs on the response — redacting emails, cards, SSNs, and encrypting fields before the agent ever sees them.
How it works
- Your app writes raw objects (via Maskura's write path, your own S3 client, or a pre-existing bucket).
- An AI agent GETs the object through Maskura, setting
x-maskura-process: read. - Maskura fetches the raw bytes, runs the PII/encryption pipeline, and returns the scrubbed result.
- The underlying object is unchanged — your app keeps full-fidelity data; the agent gets a safe projection.
Example
# Plain read — raw data (only your app should do this)
curl https://api.s4.231self.com/customers/customer-1.json \
-H "x-maskura-access-key: s4_..." \
-H "x-maskura-secret-key: s4s_..."
# → {"email":"alice@example.com","card":"4111111111111111","note":"hi"}
# Agent read — scrubbed on the way out
curl https://api.s4.231self.com/customers/customer-1.json \
-H "x-maskura-access-key: s4_..." \
-H "x-maskura-secret-key: s4s_..." \
-H "x-maskura-process: read"
# → {"email":"[REDACTED_EMAIL]","card":"[REDACTED_CARD]","note":"hi"}Via MCP
The public maskura-mcp stdio server's maskura_get_object tool accepts process: true, which sends x-maskura-process: read to the gateway:
// "Read customers/export.json with the configured read pipeline"
maskura_get_object(bucket="customers", key="export.json", process=true)Joinable reads (stable encryption)
Sometimes the agent doesn't just need safe data — it needs to join it (merge on a shared key, dedupe, or pivot). Redaction destroys that: every email becomes [REDACTED_EMAIL], so everything joins to everything. Envelope encryption (randomized AES-GCM) does too.
For joinable output, configure stable-encrypt before any redactor that would replace the join field, then set x-maskura-stable-fields alongside x-maskura-process: read. The header supplies field names to the plugin; it does not reorder the pipeline or automatically bypass redaction. With that ordering, stable-encrypt applies deterministic AES-SIV, so the same value yields the same ciphertext without exposing plaintext.
# Agent joins two datasets on email, without seeing any email
curl https://api.s4.231self.com/customers/c1.json \
-H "x-maskura-access-key: s4_..." \
-H "x-maskura-secret-key: s4s_..." \
-H "x-maskura-process: read" \
-H "x-maskura-stable-fields: email"
# → {"email":"ZuXfsc392EIpZaxcMJSPd1NoYfhadX7aR6+umdNkHv4=","note":"first"}
curl https://api.s4.231self.com/customers/c2.json \
... -H "x-maskura-process: read" -H "x-maskura-stable-fields: email"
# → {"email":"ZuXfsc392EIpZaxcMJSPd1NoYfhadX7aR6+umdNkHv4=","note":"second"}
# the email ciphertext is identical -> joinableThe ciphertext is deterministic for the configured stable key, so reads using the same configuration agree. This is the joinable + safe pattern when the pipeline is ordered as described above.
Why this matters
- Single source of truth — no duplicate cleaned datasets to keep in sync.
- Zero raw exposure — the model/agent context never contains PII.
- Same pipeline — redaction and encryption rules are identical to write-time.
- Joinable when configured — stable-encrypt preserves equality when it runs before redaction on the selected fields.
- Works with existing buckets — raw data written by any client is handled.
Details
- Header:
x-maskura-process: read(ortrue) on GET. The legacyx-s4-*headers remain aliases; do not send conflicting old and new values. - Hosted PUT and GET requests are capped at 64 MiB. Text records and complete JSON documents are capped at 8 MiB.
- Joinable mode: order stable-encrypt before redaction, then add
x-maskura-stable-fields: email,card(comma-separated). The header does not skip or reconfigure other plugins. - Transformed GET applies to your configured storage backend. Presigned backend URLs support passthrough only.
- If the pipeline errors, the processed read fails closed; Maskura does not fall back to returning raw bytes.
- When a plugin cannot be streamed safely, Maskura may stage the transformed read in a temporary encrypted local spool before returning any response bytes. Spool data shares a 256 MiB process quota, and stale artifacts are removed within a bounded cleanup window.
- Envelope encryption requires the reading key to have a public key attached (see Envelope Encryption); stable-encrypt derives its key from the API key secret.