Python SDK: CodexClient auto-approves all command/file approval requests by default
What issue are you seeing?
In the openai-codex Python SDK, CodexClient installs a default approval handler that auto-accepts every server-initiated approval request when the caller does not supply their own handler.
CodexClient._default_approval_handler returns {"decision": "accept"} for both item/commandExecution/requestApproval and item/fileChange/requestApproval, and returns a malformed {} (no decision) for other approval methods such as item/permissions/requestApproval.
These server-initiated requests are the sandbox-escalation gate — they are only sent when an action would exceed the active sandbox/approval policy. With the server default approvals_reviewer = user, the decision is meant to come back to the client. The SDK answers accept automatically, with no inspection of the command, cwd, or requested permissions, and without the caller ever opting into auto-approval.
Impact: a CodexClient-based integration silently grants any sandbox escalation the agent requests. If the agent processes untrusted input (repository files, fetched web content, tool output), prompt injection can drive it to request — and automatically receive — network egress, writes outside the workspace, or elevated command permissions, with no human or Guardian review.
Scope (stated plainly): this is specific to the Python SDK's low-level CodexClient. The shipped end-user surfaces are not affected — CLI/App/Web (codex-rs) default to AskForApproval::OnRequest and prompt; the TypeScript SDK delegates approval policy to the binary; and the high-level Codex API defaults to ApprovalMode.auto_review (server-side Guardian). Exposure is greatest for direct CodexClient use and/or configs where approvals_reviewer = user.
What steps can reproduce the bug?
Minimal, self-contained — no codex binary, API key, or network required. It drives the SDK's real approval-routing path (_handle_server_request ->_default_approval_handler):
from openai_codex.client import CodexClient
client = CodexClient() # no approval_handler supplied
req = {"method": "item/commandExecution/requestApproval", "id": 1, "params": {}}
print(client._handle_server_request(req))
# -> {'decision': 'accept'} # the SDK approves the escalation, no review
item/fileChange/requestApproval behaves the same; item/permissions/requestApproval returns {} (no decision).
What is the expected behavior?
With no explicit approval_handler, the SDK cannot know the caller's intent, so it should decline the escalation rather than silently grant it. Auto-approval should be an explicit opt-in the caller passes as a handler.
Expected for the snippet above: {'decision': 'decline'} (and a well-formed decline for unrecognized approval methods rather than {}).
Additional information
Root cause — sdk/python/src/openai_codex/client.py:
def _default_approval_handler(self, method, params):
"""Accept approval requests when the caller did not provide a handler."""
if method == "item/commandExecution/requestApproval":
return {"decision": "accept"}
if method == "item/fileChange/requestApproval":
return {"decision": "accept"}
return {}
Proposed fix (high-level): make the no-handler default decline, which also fixes the malformed {}:
def _default_approval_handler(self, method, params):
"""Decline approval requests when the caller did not provide a handler."""
return {"decision": "decline"}
Callers wanting auto-approval for trusted, headless automation pass an explicit handler, e.g. CodexClient(approval_handler=lambda method, params: {"decision": "accept"}). Note this is a behavior change for any caller currently relying on the implicit auto-accept.
I've prepared a candidate one-line fix plus a regression test on a branch, and am happy to open a PR if the team would like one:
https://github.com/Pushpendra100/codex/tree/fix/sdk-default-decline-approvals
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗