HiddenLayer AISec Detection v2 on TrueFoundry AI Gateway via a deployable FastAPI wrapper.
Deploy the integrations/hiddenlayerFastAPI wrapper on any public HTTPS host — TrueFoundry, Docker, Render, ECS, Cloud Run, or on-prem. The gateway calls it at llm_input / llm_output via the Custom Guardrail contract; the wrapper forwards traffic to HiddenLayer AIDR Detection v2 and returns verdict JSON on HTTP 200.
HiddenLayer AISec is a runtime security platform for LLM applications. Policies are defined in the AISec Console; the wrapper does not embed policy logic. It authenticates with OAuth2 client credentials, scopes every call to your project via HL-Project-Id, and maps HiddenLayer v2 outcomes to the TrueFoundry guardrail contract.
Input validation — blocks prompt injection, jailbreak, and other threats before the model runs (interaction-evaluations + inline fallback).
Input mutation — redacts PII and sensitive content in the prompt before it reaches the model (request-evaluations).
Output validation — blocks threats in the model response using full interaction context.
Output mutation — redacts sensitive content in the model response (response-evaluations).
Wire validate rails for hard stops. Add mutate rails when you need redacted text forwarded to the model or caller (tokens like [REDACTED:EMAIL_ADDRESS]).
The wrapper always returns HTTP 200 and signals the policy decision in the JSON body. Infrastructure failures return HTTP 5xx. See Custom guardrail response contract.
GET /health — health check (no auth). GET /debug/loaded-config — bearer-gated diagnostics (reports whether credentials and project are configured; never returns secret values).All POST routes require Authorization: Bearer <WRAPPER_API_KEY>. If WRAPPER_API_KEY is missing, empty, or still the example placeholder, every guardrail route returns HTTP 503 (fail closed on misconfiguration). For local dev without a key, set ALLOW_NO_AUTH=true — never use that in production.
HiddenLayer OAuth2 credentials — HIDDENLAYER_CLIENT_ID and HIDDENLAYER_CLIENT_SECRET from the AISec Platform Console (API Keys tab).
HIDDENLAYER_PROJECT_ID — project ID or alias sent as HL-Project-Id on every detection call. This selects the AISec policy applied to each request.
WRAPPER_API_KEY — shared secret; the gateway sends it as Authorization: Bearer … when calling the wrapper.
Public HTTPS URL for the deployed wrapper.
HiddenLayer credentials, project ID, region, and API/auth base URLs are resolved only from service environment variables — the per-request dashboard config JSON cannot override them (prevents SSRF and credential exfiltration). Do not put secrets in the TFY dashboard config field or in client requests. Never deploy without a real WRAPPER_API_KEY; do not set ALLOW_NO_AUTH or HIDDENLAYER_SKIP_PROJECT_ID_CHECK in production.
Set WRAPPER_API_KEY in .env before testing guardrail routes. Alternatively, add ALLOW_NO_AUTH=true for keyless local dev only.Smoke test:
curl http://localhost:8000/healthcurl -X POST http://localhost:8000/validate-input \ -H "Authorization: Bearer $WRAPPER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"requestBody":{"model":"gpt-4o","messages":[{"role":"user","content":"What is the capital of France?"}]}, "context":{"user":{"subjectId":"u1","subjectType":"user"}}}'# -> {"verdict":true}
Docker or any cloud host:Build and run the container on ECS, Cloud Run, Kubernetes, Render, or any platform with a public HTTPS URL. Put TLS in front of the service; the gateway must reach paths such as https://<host>/validate-input.
Deploy on TrueFoundry (optional)
Set TFY_WORKSPACE_FQN, TFY_PUBLIC_HOST, TFY_PUBLIC_PATH, and secret FQNs in .env. Create secrets hiddenlayer-client-id, hiddenlayer-client-secret, and wrapper-api-key under group hiddenlayer-guardrails-tfy in Platform → Secrets, then:
Optional per-request overrides for metadata and policy knobs. Credentials, project ID, region, and API hosts must stay in service env vars — they cannot be set here.
true to allow traffic when HiddenLayer is unavailable (default: true unless env overrides)
allow_detect_on_validate
true to pass DETECT on validate rails
Per-request config overrides env defaults for these fields when present, except HIDDENLAYER_FAIL_OPEN_ON_UNAVAILABLE which takes precedence over fail_open_on_unavailable in config.
Guardrail routes return HTTP 503 when WRAPPER_API_KEY is missing, empty, or still the example placeholder. Set a strong key on the service, or ALLOW_NO_AUTH=true for local dev only. Check GET /debug/loaded-config — wrapper_auth_enabled should be true in production.
401 Unauthorized from the wrapper
The Authorization: Bearer … value the gateway sends doesn’t match the wrapper’s WRAPPER_API_KEY env var. Three places must agree:
The secret or env var on the deployed wrapper.
The Custom Guardrail Config’s Headers or Auth Data → Custom Bearer Auth field value.
Any platform secret FQN referenced at deploy time.
Gateway allows despite verdict: false
The wrapper signals rail decisions via {"verdict": false} on HTTP 200. Confirm by curling the wrapper directly — if you get 200 + {"verdict": false} but the gateway still returns a completion, the gateway is the issue.Workaround: switch the Custom Guardrail Configs’ Enforcing Strategy to Enforce. See Enforcing Strategy.
DETECT findings block traffic but I want observe-only
Set HIDDENLAYER_ALLOW_DETECT_ON_VALIDATE=true on the wrapper, or "allow_detect_on_validate": true in dashboard config. Validate rails will pass DETECT outcomes; REDACT and BLOCK still deny.
Validate blocks instead of redacting PII
Use /redact-input and /redact-output rails with Operation: Mutate instead of validate rails. Validate rails deny on REDACT; mutate rails apply the redacted body.
HiddenLayer API unavailable (5xx)
Check wrapper logs for upstream errors. By default the wrapper fails open on HiddenLayer 5xx/timeout — traffic passes unscanned and returns {"verdict": true}. With dashboard Fail on error: false, the gateway also allows the LLM call when the wrapper returns 5xx.For safety-critical rails, set HIDDENLAYER_FAIL_OPEN_ON_UNAVAILABLE=false on the service or "fail_open_on_unavailable": false in dashboard config (env wins if both are set). That blocks traffic when HiddenLayer is unavailable.