Codex CLI

Codex CLI is OpenAI’s agentic coding tool: it reads your repository, runs commands, and applies patches in a loop. It talks to a model provider defined in ~/.codex/config.toml, which means putting it behind the firewall is a matter of defining one more provider — the gateway — and selecting it. No proxy, no plugin.

Warning Codex CLI speaks the OpenAI Responses API and nothing else — its provider block accepts no other wire_api. On the gateway, only the openai provider serves the responses surface. You cannot point Codex at groq, openrouter, mistral or any other provider through the firewall: those serve chat only, and the gateway will answer 404 unsupported_api.

Why put Codex CLI behind the firewall

  • Your provider key never sits in the agent’s config. config.toml references VULNETIX_API_KEY. Your OpenAI key stays in the KMS-encrypted BYOK vault and is decrypted just-in-time by the gateway, on the server side of the request.
  • Every prompt the agent sends is screened by your guardrails — and for an agent, “prompt” means far more than what you typed. The contents of every file it reads and the output of every command it runs are fed back into the conversation as tool results, and those go through your guardrails too.
  • Provider and model policy is enforced centrally. Codex cannot silently switch to a model your organisation has not approved: the decision is made at the gateway, on every request, not in a local config file a developer can edit.

Quick start

CLI
vulnetix ai-firewall key set openai --from-env OPENAI_KEY
vulnetix ai-firewall install codex --model gpt-4o-mini

That writes a managed block into ~/.codex/config.toml. The --model you pass is validated against your organisation’s policy before the file is touched, so you cannot wire a model the gateway would refuse at request time.

vulnetix ai-firewall install codex --dry-run

--dry-run prints the exact file and the exact block it would write, and changes nothing.

Then make sure your Vulnetix API key is in the environment Codex inherits — the config block refers to it by name, it does not contain it:

export VULNETIX_API_KEY=vlx_...
Tip vulnetix ai-firewall install shell adds a managed block to your shell rc that exports VULNETIX_API_KEY for you, so every client on the machine picks it up.
Manual

Edit ~/.codex/config.toml and define the gateway as a model provider, then select it at the root of the file:

model = "gpt-4o-mini"
model_provider = "vulnetix-openai"

[model_providers.vulnetix-openai]
name = "Vulnetix AI Firewall"
base_url = "https://guardrails.vulnetix.com/openai/{orgUuid}/v1"
wire_api = "responses"
env_key = "VULNETIX_API_KEY"

Four things to get right:

  1. wire_api = "responses". Codex requires the Responses API. chat will not work here.
  2. The base URL does end in /v1 — this is the OpenAI shape. (Anthropic’s is the one that does not; see base URLs.)
  3. The provider slug in the URL is openai, because it is the only provider that serves responses.
  4. env_key = "VULNETIX_API_KEY" names an environment variable. Codex reads the key from your environment at run time — the key itself is never written into config.toml.
export VULNETIX_API_KEY=vlx_...

How it works

Codex CLI sends POST /v1/responses to https://guardrails.vulnetix.com/openai/{orgUuid}/v1 — the gateway’s responses surface. The gateway authenticates the Vulnetix API key to your organisation, applies provider and model policy, runs your guardrails over every text segment in the request, decrypts your OpenAI key from the vault, and forwards the call. Prompts and completions are never logged.

No local proxy is required. Codex is talking to the gateway directly, over the same protocol it would use to talk to OpenAI, using a provider mechanism it already has.

Guardrails behave identically on responses as they do on chat and messages. A rule you wrote for a curl covers a Codex turn without modification.

Verify

vulnetix ai-firewall status

Codex should show as wired:

clients
  codex          wired          ~/.codex/config.toml
                                https://guardrails.vulnetix.com/openai/{orgUuid}/v1

points elsewhere means config.toml exists but names a different base_url — an OpenAI endpoint, or another gateway. That client raises the bypasses_firewall check, and it is the one to act on.

Limitations

Once wired, every model request Codex CLI makes goes through the firewall. Codex has no built-in completion or background feature that uses a different credential; the model_provider you selected is the one it uses.

Two honest caveats:

  • The arguments the model generates for a tool call are not scanned. Prompt content and tool results are; the shell commands and patches the model emits as tool-call arguments are not.
  • A developer can edit config.toml. Switching model_provider back to OpenAI’s own is a one-line change. The firewall is a control, not a cage — vulnetix ai-firewall status and its bypasses_firewall check exist so you can find that machine.

Common errors

401 — invalid Vulnetix API key

{
  "error": {
    "message": "invalid Vulnetix API key",
    "type": "authentication_error",
    "code": "invalid_api_key"
  }
}

Two causes, and they look identical from the outside.

The first is the two-keys confusion: VULNETIX_API_KEY is holding an OpenAI key (sk-…) instead of your Vulnetix API key. The gateway authenticates you with the Vulnetix key and supplies the OpenAI key itself, from the vault. Your provider key belongs in the vault, never in the agent.

The second is that VULNETIX_API_KEY is not set at all in the shell Codex was launched from — env_key names the variable, so an unset variable means an empty credential. The CLI catches this locally as the key_env_unset check.

Fix:

  1. Store your OpenAI key in the vault: vulnetix ai-firewall key set openai --from-env OPENAI_KEY.
  2. export VULNETIX_API_KEY=vlx_... — or run vulnetix ai-firewall install shell so it is exported for every session.
  3. Confirm with vulnetix ai-firewall status: no key_env_unset check should remain.
  4. Start a new terminal session, so Codex inherits the variable.

403provider_key_missing

{
  "error": {
    "message": "no OpenAI API key configured for your organisation: add one with 'vulnetix ai-firewall key set openai' or at https://www.vulnetix.com/vdb-ai-firewall#byok",
    "type": "permission_error",
    "code": "provider_key_missing"
  }
}

You are authenticated, but your organisation has no OpenAI key in the vault, so the gateway has nothing to forward the request with.

Fix:

  1. export OPENAI_KEY=sk-...
  2. vulnetix ai-firewall key set openai --from-env OPENAI_KEY
  3. vulnetix ai-firewall status — the openai row should now show a stored key.

Note that vulnetix ai-firewall install codex would have refused to wire a provider with no stored key in the first place. Seeing this error usually means the key was removed after the config was written.

403model_not_allowed

{
  "error": {
    "message": "model gpt-4.5-preview is not in the organisation allowlist",
    "type": "permission_error",
    "code": "model_not_allowed"
  }
}

Your organisation runs an allowlist for openai, and the model in config.toml is not on it. (A model that is explicitly denied returns model_denied instead.)

Fix:

  1. Run vulnetix ai-firewall get to see which models your policy permits.
  2. Re-wire with an approved model: vulnetix ai-firewall install codex --model gpt-4o-mini. The CLI validates the model against policy before writing, so this cannot leave you in the same state.
  3. If the model should be allowed, an administrator adds it to the policy.

404unsupported_api

{
  "error": {
    "message": "provider groq does not support the OpenAI Responses API (POST /v1/responses). Use POST /v1/chat/completions for groq, or use the openai provider, which serves the Responses API: https://guardrails.vulnetix.com/openai/{orgUuid}/v1",
    "type": "not_found_error",
    "code": "unsupported_api"
  }
}

You pointed Codex at a provider that does not serve the responses surface. Only openai does. The CLI catches this class of mistake locally, before you send a request, as the wire_unsupported check.

The same code also appears if the base URL is missing its /v1 suffix — the OpenAI shape requires it, unlike Anthropic’s.

Fix:

  1. Open ~/.codex/config.toml.
  2. Confirm base_url is https://guardrails.vulnetix.com/openai/{orgUuid}/v1 — the slug openai, and with the trailing /v1.
  3. Confirm wire_api = "responses".
  4. Re-run vulnetix ai-firewall install codex to have the CLI write it correctly.