Skip to main content

Scanning Flow

Prompt Scanning

Response Scanning (Stop — post-stream)

Post-stream detection

The Stop hook fires after the response streamed to the user — Codex has no streaming interception hook. On an AIRS block verdict the hook returns continue: false with a stopReason, terminating the turn so the session does not build on flagged content. The displayed text cannot be retracted. The Stop hook is always fail-open: config or API errors never terminate the turn.

Code Extraction Strategy

The code extractor processes final responses using three strategies in priority order:

  1. Fenced code blocks -- ```language ... ``` with language detection
  2. Indented code blocks -- 4+ leading spaces
  3. Heuristic fallback -- content matching code indicators (imports, function definitions, braces) above a character threshold

Extracted code is joined with \n\n---\n\n separators and sent in the code_response field, which triggers WildFire/ATP malicious code scanning on the AIRS side.

MCP Tool Scanning (PreToolUse — can deny)

Tool Output Scanning (PostToolUse — observe-only by policy)

Observe-only by policy

Codex can block tool results in PostToolUse (replacing the result with hook feedback), but this project runs the hook observe-only: the completed tool call's side effects can't be undone anyway, so violations are logged and warned for audit. Local Bash output and apply_patch edits are not scanned at all — only MCP tools match.

Content Splitting

AIRS FieldContentDetections
promptUser's prompt textPrompt injection, DLP, toxicity, custom topics
responseNatural language from the final responseDLP, toxicity, URL categorization
code_responseExtracted code blocks from the final responseMalicious code (WildFire/ATP)
tool_eventMCP tool inputs and outputs (metadata.method: "tools/call")Prompt injection, DLP, malicious parameters
Why split content?

Sending code separately in code_response enables dedicated malicious code detection engines (WildFire, ATP) that don't run on natural language content. This catches things like reverse shells, credential stealers, and obfuscated payloads in generated code. Similarly, tool_event is routed to a security profile tuned for tool-call patterns.

AIRS Correlation

Every scan carries correlation IDs so all activity from one Codex session groups together in AIRS:

HookAIRS session_idAIRS tr_id
UserPromptSubmitCodex session_idCodex turn_id
PreToolUse / PostToolUseCodex session_idCodex turn_id:tool_use_id
StopCodex session_idCodex turn_id

When Codex omits fields, the transaction ID falls back through turn_idtool_use_idsession_id, and the AIRS session ID falls back to app-user:date.