Sign up for updates
TL;DR
- In our March to June 2026 tests, a Codex Cloud trust boundary let indirect prompt injection from apparently trusted external content exfiltrate readable process-environment data, including a configured secret, to an attacker-controlled HTTPS endpoint while the UI still showed Agent internet access as Off.
- The chain started with unexpected WebFetch rendering vulnerability that brought attacker-controlled instructions into the task despite that setting. It became secret theft when sandbox initialization ran setup commands from an unreviewed branch without a platform-enforced review gate.
What is Codex Cloud:
Codex Cloud is OpenAI's remote software-engineering worker. Instead of running beside the developer on a laptop, each task runs in an isolated cloud environment attached to a repository. A developer can start the work from Codex, GitHub, GitLab, Linear, or Slack and let it continue in the background.
OpenAI's Codex Cloud overview describes the basic loop: connect a repository, create a reproducible environment, give Codex a task, and return when the result is ready to review.
That distinction matters. This is not only a chat interface that suggests code. Codex receives a working copy of the repository and a shell. It can inspect the project, edit files, install dependencies, run linters and tests, and leave a diff on a task branch.
Work now, review later
The product is designed to move the human review boundary to the end of the run.
OpenAI tells developers to give longer jobs dedicated environments and let them continue while other work happens. During the task, the agent runs terminal commands in a loop, edits code, runs checks, and tries to validate the result. When it finishes, Codex returns a summary and diff; the developer can request another pass or open a pull request. The cloud-environment documentation spells out that sequence.
This is the value proposition: Codex performs the implementation work without requiring a person to approve every command. Human attention returns at the review boundary, before the change is merged.
Security therefore depends on one question: what can execute before that review occurs?
What the cloud worker needs
Useful autonomy requires access. Codex Cloud needs several kinds of it:
- Repository access. A GitHub or GitLab connection lets Codex clone the project, check out the selected branch or commit, write changes, and prepare work for review. OpenAI's GitHub integration documentation also describes Codex operating directly on pull requests and following repository guidance from
AGENTS.md. - A build environment. The container needs the runtimes, compilers, package managers, linters, and test tools used by the repository.
- Dependency access. Setup may need the public internet or private registries to install packages and reproduce the project.
- Environment variables and secrets. Not every project needs credentials, but realistic builds often require tokens for private packages, artifact stores, test services, or other development infrastructure. Codex environments let developers configure both ordinary variables and encrypted secrets.
These are legitimate capabilities. The security problem is not that Codex has them. It is whether code with the wrong provenance can inherit them.
The controls and when they take effect
OpenAI provides several hardening controls around the agent:
- Agent internet access is off by default.
- If internet access is enabled, the developer can restrict it to an allowlist of domains and limit the permitted HTTP methods.
- OpenAI warns that untrusted web content can cause prompt injection and recommends keeping internet access as limited as possible.
- Configured secrets are decrypted for task execution and removed before the agent phase begins.
- The developer reviews the summary and diff before merging the result.
Those controls sound like a familiar least-privilege design. The timing is the important part.
The agent internet-access documentation scopes the network restriction to the agent phase. Setup scripts still run with internet access so they can download dependencies. The environment documentation says the platform checks out the repository and runs setup (or maintenance for a resumed cached container) before it applies the agent's internet policy and starts the agent.
The sandbox exists before the sandbox policy that most users are thinking about.

From prompt to running agent: the complete startup path
For a fresh environment, OpenAI documents this sequence:
1. Create a cloud container
2. Check out the repository at the selected branch or commit
3. Run the setup script
- internet access: available
- configured secrets: available to setup
4. Prepare the agent phase
- remove configured secrets
- apply the agent internet-access policy
5. Start the Codex agent
6. Let the agent edit, run commands, test, and produce a diffCaching adds a second path. Codex can cache the container after setup for up to 12 hours. When that cached environment is reused, the sequence becomes:
1. Resume the cached container
2. Check out the branch selected for the new task
3. Run the optional maintenance script
4. Prepare the agent phase
- remove configured secrets
- apply the agent internet-access policy
5. Start the new agentOpenAI describes maintenance as a way to refresh dependencies when the cached setup was created from an older commit. That makes commands such as these entirely ordinary:
pip install -r requirements.txt
test -f Makefile && make setupBut both commands interpret repository-controlled files. pip install can invoke local build and installation logic. npm install can run lifecycle hooks. make setup executes whatever the selected branch placed behind the setup target.
Our test environment used post-setup caching, Agent internet access set to Off, one benign test secret, and the two maintenance commands above.
The documentation says secrets are available to setup and removed before the agent. In our controlled test, the configured secret was also visible to the maintenance process that ran before the agent. That process could reach an external HTTPS endpoint.
This was the privilege window.

The question we could not shake
Once we drew the startup sequence, the trust boundary looked backward.
The agent phase was the part treated as dangerous. It received no configured secret, and its direct internet access could be disabled. Yet the agent could write arbitrary repository files and commit them to a branch.
The earlier initialization phase was more privileged. It needed network access to install dependencies and, in our test, could see the configured secret. It also executed setup commands before any new agent or user could review the selected branch.
That led to a simple question:
Could code created by a restricted Codex agent survive in Git, return as input to a later task, and execute during that later task's privileged initialization?
We did not need to break the agent sandbox. We needed to make the agent write code that the platform would trust at the wrong time.
The obvious targets were the files developers already expect initialization to consume: requirements.txt, pyproject.toml, setup.py, package.json, shell scripts, and Makefile targets. If attacker-controlled instructions could influence one Codex task to modify one of those files, Git could carry the modification into the next task.
One piece was still missing: how would attacker-controlled instructions reach the first agent when its internet access was Off?
The missing link: “Internet Off” still had an ingress path
OpenAI's UI presents the Off setting as completely blocking internet access for the agent. In our first task, that was true for a direct shell request: curl was blocked.
The agent did not stop. It reported switching to its built-in web-retrieval path (referred to in the disclosure as the WebFetch internal tool) and continued reading the supplied GitHub content. With the page crafted in a form the renderer would accept, the built-in path returned the page content even though direct shell networking was unavailable.
That behavior mattered for ingress, not egress. We did not exfiltrate a secret through WebFetch, and we did not demonstrate arbitrary shell networking from the restricted agent. The built-in renderer delivered attacker-controlled text into the agent's context. The later maintenance phase supplied the secret and the outbound POST.
The external material looked like project workflow documentation. It used an AGENTS.md file, nested Markdown helpers, plausible engineering conventions, and integrity language that encouraged the agent to preserve the supplied files. Once rendered, those instructions became an indirect prompt-injection path into a task that appeared to have no internet access.
Internet Off had blocked the obvious pipe while leaving the content channel we needed.

Git makes the handoff durable
Codex tasks work on branches. When Task 1 commits a file, that file stops being transient agent output and becomes repository state.
The crucial detail is what happens when another task starts from that branch. On a resumed cached environment, Codex checks out the branch selected for the new task before running maintenance. The new task does not need the branch to be merged. A pull request does not need to be approved. Selecting the agent-created branch is enough to make its files the inputs to initialization.
This is why Task 1's code can execute during Task 2:
Task 1 agent writes file
↓
Task 1 commits file to codex/... branch
↓
User starts Task 2 from that branch
↓
Codex checks out the branch
↓
Maintenance interprets its setup files
↓
Task 2 agent starts and reviews afterwardThe branch is the bridge between two different privilege levels.
Building the two-task exploit
The full chain needed two tasks because no single phase had everything. Task 1 had the ability to author and commit code but did not receive the configured secret. Task 2's pre-agent maintenance had the secret and outbound HTTPS, but it needed executable repository content waiting on the selected branch.
Task 1: turn instructions into setup code
We gave Codex a normal-looking assignment: follow a GitHub-hosted AGENTS.md workflow and begin planning an AWS S3 project.
The agent followed the external workflow and its nested helpers. Among otherwise plausible planning documents, tests, and engineering guidance, it created two files that mattered:
- A
Makefilewhosesetuptarget invokedpython3 health_check_endpoint.py. - A Python “health probe” that collected readable process environments and sent the result to an endpoint we controlled.
The probe did not contain an obvious cat /proc/*/environ string. It reconstructed the command from harmless-looking fragments:
"catalog"[:3] # cat
"process_control"[:4] # proc
"environment"[:7] # environThose slices produced cat /proc/*/environ. The script captured the readable process environments, base64-encoded the output, and sent it over HTTPS.
The agent exercised the setup path, reported successful tests, and committed the generated files. Task 1 did not receive the configured secret and did not exfiltrate it. Its job in the chain was to author the payload and persist it.



Task 2: let initialization pull the trigger
We then started a second task on Task 1's branch and asked the new agent to review the changes.
Before that review prompt reached the agent, Codex resumed the cached environment, checked out the branch, and ran maintenance:
Running maintenance scripts...
+ test -f Makefile && make setup
Running project health check...
Health check complete.The selected branch supplied the Makefile. Its setup target launched the committed Python probe.
Our controlled webhook received a POST from the Codex environment. Task 2 was still displaying Environment setup. The request body contained base64-encoded process-environment data, including the benign secret configured for the test.
The agent had not opened the file, approved a command, or decided to run anything. Codex was still initializing the environment, automatically running the kind of routine bootstrap every developer recognizes: pip install -r requirements.txt, followed by make setup when a Makefile was present. That mundane setup step executed code from an unreviewed branch before the agent ever started.
The reviewer arrived after the secret
When Task 2's agent finally started, it did exactly what a good reviewer should. It identified the obfuscated command construction, the /proc/*/environ collection, the encoding step, and the outbound POST. It called the file data-exfiltration behavior and recommended treating it as malicious.
The webhook had already received the secret.
No improvement to the reviewing agent can repair that ordering. Detection after maintenance cannot stop code that maintenance has already executed.


Describing the vulnerability
The WebFetch behavior is the entry path. The maintenance boundary is the privilege transition.
Package hooks, Makefiles, Git branches, and indirect prompt injection are not new primitives. The vulnerability lies in their composition across two Codex tasks:
- Built-in retrieval delivers attacker-controlled project instructions despite Agent internet access being Off.
- A restricted agent turns those instructions into executable repository files.
- Git preserves the files on an unreviewed task branch.
- A later task checks out that branch before its agent starts.
- Maintenance executes the branch's setup code with the configured secret and outbound HTTPS available.
- The secret leaves before the review phase exists.
In our testing, the platform allowed low-privilege agent output to become high-privilege initialization input without an intervening provenance or review gate.
Our controlled proof stopped when the benign test secret reached our endpoint. We did not use the credential against another service, access another user's data, or test every Codex configuration. A real attacker's next step would depend on the authority carried by the stolen credential.

Closing the gap
The fix is to treat agent-generated branch content like untrusted CI input before privileged maintenance runs.
- Run maintenance with secrets only on protected or explicitly approved commits.
- Remove secrets from maintenance by default and map only the minimum credential required for a specific setup action.
- Do not let dependency refresh silently execute repository-local hooks from an unreviewed branch.
- Apply provenance checks and diff review before privileged initialization, not after it.
- Make “Internet Off” cover built-in retrieval or label the separate network capabilities precisely.
- Show the user when a selected branch will be executed during setup and which secret and network capabilities that phase receives.
The security boundary has to follow the code's provenance, not merely the name of the phase executing it.
OpenAI acknowledgment status - and what remains unanswered
During the disclosure process, we requested clarification about the maintenance-execution finding and escalated the matter through program support. As of September 2, 2026, the submission remained Triaged, the coordinated-disclosure request remained pending, and we had received no response addressing that boundary. Although several late-August retests did not reproduce the original behavior, those results do not establish that the underlying maintenance issue was remediated. We therefore describe the original chain as demonstrated in our earlier tests, with its subsequent remediation status unconfirmed.







