Protect Sensitive Data
This tutorial exercises the demo bundle’s content controls. The security team’s detectors and gate decide what may leave a sandbox, regardless of which tool or service the agent calls.
After completing it, you understand:
- How annotators, a control rule, effects, and findings work together.
- Why the same secret is denied in a tool call but redacted in a plain request.
- How a redaction that cannot be applied fails closed.
- How each outcome appears in the audit trail.
Prerequisites
- APF running with the demo bundle, or the revision from Your First Signed Policy, and registered with OpenShell as described in Add APF to OpenShell. The demo sandbox policy allows
POST /anythingonhttpbin.organd routes the host to APF. - A workload image with
curlat/usr/bin/curland asandboxuser and group. - Terminals set up as in Set Up Each Terminal, and
jq.
httpbin.org/anything echoes the request it receives, which makes each rewrite visible.
Redact a Credential from a Plain Request
The echoed data is APF’s redaction notice, not your body, and the echoed headers include X-Openshell-Middleware-Apf-Event: demo_secret. The credential never left the sandbox.
The authorization record has "decision":"allow", "reason_code":"middleware.allowed_with_findings", a finding of kind secret_detected with label demo_secret and severity critical, and effects.payload_replaced: true.
Withhold Personal Data
The echoed JSON has its text field replaced with the sanitization notice from redact-pii-body, and priority is unchanged. The record carries a finding of kind pii_redacted, label pii_in_body_text, severity medium, and effects with patch_count: 1 and a patch record for /text.
See a Redaction Fail Closed
Send personal data in a body without a text field:
The request is denied and never reaches httpbin. redact-pii-body must replace /text, the body has no such field, and APF refuses to forward a request it could not rewrite. The record has "decision":"deny" and "reason_code":"middleware.effect_application_failed".
To redact any body shape, use a whole-body replacement, as redact-wholesale does.
Deny a Tool Call That Carries a Credential
Send an MCP tool call for a granted tool, with a credential in its arguments:
The tool is granted by github-grants, but the content gate’s forbid fires because the call carries a secret. Evaluation stops and the request is denied. The record has "decision":"deny", "verb":"tool.github_repo_read", an error.message of security-content-gate/deny-secret, and the secret_detected finding.
Tool calls are denied rather than redacted because rewriting a tool’s arguments could change what the tool does.
Next Steps
- To write your own detectors, refer to Annotators.
- To change how detections are handled, refer to Content Controls.