Policy fields
You manage saved policies in app.ngrok.ai under Firewall, or with the Firewall Policies API. Each field shows its dashboard label first, then its name in theplugins field.
The API uses the same names, except that it spells on_error as onError and puts every rule in one rules list, where each rule sets its tier to hardDeny, softDeny, or allow.
Rule fields
Each rule type takes only its own match field.
For example, a regex rule with
instructions is rejected.
Matching details
- Tool names match the whole name and are case-sensitive.
*matches any characters, somcp__github__*matchesmcp__github__create_issue. - Regex patterns are case-sensitive unless they start with
(?i). Against a tool call, the pattern matches the tool name, a space, and the raw JSON arguments. Block rules also match the arguments with JSON escapes decoded. - Regex rules on request parts match all the text of each part, across every message, joined with newlines.
- In a Responses request,
instructionsandprompt.variablescount as messages, call items as assistant turns, and*_call_outputitems as tool results. Tool definitions include tools that a tool search or an MCP tool list added to the conversation. - In a Gemini request,
systemInstructionand thecontentsparts count as messages,functionResponseparts as tool results, andfunctionDeclarationsas tool definitions. Images, audio, and video have no text to read. Firewall can’t read a PDF or other file part, so On error decides for rules that read the part. - Decision rules on request parts read the system and developer messages plus the newest input: the latest user message and any tool results it carries.
They read up to about 41 KB of text.
When the text is longer, the
Ngrok-AIG-Firewall-Requestheader reports a partial read.
The plugins field
Add a plugins array to a /v1/chat/completions, /v1/responses, /v1/messages, or Gemini generateContent request body to check that request with extra rules.
The gateway removes the field before it sends the request to the provider.
The rules in
plugins run on top of the saved policies that apply to the key, as described in How policies combine.
A request can add up to 48 rules, and a rule can’t reuse the ID of a rule in a saved policy.
The policy editor in the dashboard shows a ready-to-copy plugins field for the policy you’re editing, under Try it in one request.
What a blocked caller gets
A block returns HTTP200, so agents keep running and the model can react.
In Dry run, nothing is blocked, but the same results appear in the header and safeguard_results.
Blocked request
When a request rule blocks a request, the gateway doesn’t send it to the model. The response holds one assistant message with this text, in the response format of the endpoint you called:rule lists the names of the rules that blocked the request.
Each name is in brackets, with a space between names.
When Firewall couldn’t check the request and On error is Block, rule is empty and the text says the request couldn’t be checked.
Blocked tool call
When a response rule blocks a tool call, the gateway removes the call and adds this text to the assistant message. In a Responses request, an assistantmessage item with this text takes the call’s place in output.
In a Gemini request, a text part with this text takes the call’s place and keeps the call’s thoughtSignature:
rule names only rules from enforced policies.
When Firewall couldn’t check the call and On error is Block, rule is empty and the text says the call couldn’t be evaluated.
If no tool calls remain, the response ends as if the model had finished:
- Chat Completions:
finish_reasonchanges tostop. - Messages:
stop_reasonchanges fromtool_usetoend_turn.
safeguard_results
Responses carry a top-level safeguard_results array when Firewall checked something.
In a streamed response, it’s in the final chunk for Chat Completions, in the message_delta event for Messages, in the response object of the final event, such as response.completed, for Responses, and in the chunk with a finishReason for Gemini.
Request rules report one entry per rule:
A Gemini function call often has no ID.
Its entry then uses the call’s position in the response, such as
candidates[0].parts[1].
A response with no tool calls carries no dangerous_tool_use entry.
Response headers
The header lists rule IDs, while the blocked message and
safeguard_results show rule names.
The dashboard sets each ID from the rule’s name when you create the rule.
Tool call results have no header, because the gateway may already be streaming the response.
Read safeguard_results for them.
Errors
A single check that can’t run, such as a decision model timeout, doesn’t return an error.
With Block set, it blocks the request or tool call with the
200 responses described in What a blocked caller gets.