Set up a guardrail
Last validated:
Use guardrails to enforce policies on LLM requests before they leave your network. This topic covers setting up a PII-scrubbing guardrail that detects and redacts sensitive data, such as Social Security numbers, in user messages before the request reaches the provider.
Prerequisites
Before you begin, ensure you have the following:
- A running Aperture instance accessible from your device.
- A guardrail hook endpoint: an HTTP service that receives request data from Aperture, scans it, and returns an allow, block, or modify decision. The endpoint must accept POST requests and return JSON. For details on the expected request and response format, refer to the hook response format in the configuration reference.
Configure the hook endpoint
Define the guardrail in the Aperture configuration so Aperture knows where to send request data for inspection.
-
Open the Aperture dashboard at
http://<aperture-hostname>/ui/. -
Select the Settings page and open the JSON editor.
-
Add an entry in the
hookssection with the endpoint URL and credentials for your guardrail service."hooks": { "ssn-scrubber": { "url": "http://ssn-guard.example.ts.net:8080/scrub", "apikey": "<guardrail-api-key>", "fail_policy": "fail_closed", "timeout": "500ms", "preference": 10 } }Replace
http://ssn-guard.example.ts.net:8080/scrubwith the URL of your guardrail service and<guardrail-api-key>with its API key.fail_policycontrols what happens when Aperture cannot reach the endpoint.fail_closedblocks the request if the guardrail is unavailable, which is appropriate for PII scrubbing where enforcement is mandatory. Usefail_openif you prefer requests to proceed when the guardrail is down.timeoutsets the maximum time Aperture waits for a response. Keep this short (500ms to 2s) forpre_requesthooks to limit client-visible latency.preferencecontrols execution order when multiple hooks match a request. Higher values run first.
Wire the hook to requests
Connect the guardrail to incoming requests using a grant with a send_hooks entry.
-
In the JSON editor, add a grant with a
send_hooksentry that references the hook you defined."grants": [ { "src": ["*"], "app": { "tailscale.com/cap/aperture": [ { "models": "**" }, { "send_hooks": [ { "name": "ssn-scrubber", "events": ["pre_request"], "send": ["request_body", "user_message"] } ] } ] } } ]namereferences the hook key you defined in thehookssection.eventsmust includepre_requestfor the guardrail to fire before the request reaches the provider.sendcontrols what data Aperture includes in the payload to your hook.user_messageis the last message the user sent, extracted from the request body regardless of API format. Use it as the scanning surface to detect PII.request_bodyis the full request body. Use it as the modification surface: when the hook returns amodifyaction, therequest_bodyin the response replaces the original.
-
Save the configuration.
Verify the guardrail
After configuring the hook, confirm that the guardrail intercepts and processes requests.
- Send a test request through Aperture that contains a sample SSN, such as
123-45-6789. - Check the response. If your guardrail modifies the request, the LLM should receive the scrubbed content (for example,
XXX-XX-XXXX) instead of the original. - Open the Aperture dashboard and check the Captures view. The captured request body should show the modified content, not the original PII. Aperture stores the forwarded (modified) body in the capture record.
If the request passes through without modification, verify that the name in send_hooks matches the key in your hooks section and that the grant's src field includes the user who sent the request.
Variations
The PII-scrubbing example demonstrates a common use case for guardrails, but you can implement different policies by changing the hook logic and response. For example:
Block requests
Instead of scrubbing PII, your guardrail can block requests entirely. When the hook detects a policy violation, return a block response:
{"action": "block", "status_code": 451, "message": "request contains PII"}
The client receives an error response and the request never reaches the provider.
Strip tool declarations
To prevent specific tools from being available to the LLM, the hook can return a modified request_body with those tools removed from the tools array. The LLM receives the request without the stripped tools and cannot invoke them.
Next steps
- Learn how guardrails work in guardrails.
- Review the hook response format and hook chains in the configuration reference.
- For asynchronous observation and authorization hooks, refer to integrate Cerbos with Aperture or integrate Oso with Aperture.