Sign up for updates
TL;DR
- Secrets configured through Cursor's Cloud Agent Secrets system were readable in plaintext from the agent's execution environment. A test secret appeared in more than 20 processes, including the VNC server, desktop session, and file manager. Reading it required no privilege escalation.
- An indirect prompt injection in an
AGENTS.mdworkflow caused the agent to fetch and run a supposed Python health-check script. The script transmitted environment data containing the configured test secrets to our HTTPS endpoint. No command-approval prompt appeared. - This raises an architectural question: why should raw credentials be broadly available inside the same environment that executes instructions influenced by external content? The observations below describe our tested configuration; current secret types and network controls need to be evaluated separately.
The secret was also in the file manager
We expected the test credentials we configured in Cursor to be available to the software that needed them. Inspecting the Cloud Agent's process environments showed how broadly they had been distributed: the plaintext value of teams-top-secret appeared in more than 20 processes, including:
pod-daemonandexec-daemon;- the VNC server and XFCE desktop session;
- the
noVNCwebsocket proxy; - shell sessions;
- the Plank dock, file manager, and other desktop utilities.
A filtered inspection made the secret easy to locate:
cat /proc/*/environ | tr '\0' '\n' | grep -i secretThe filter selects entries containing secret; it is not a complete inventory of credentials. The underlying read collects whichever process environments the calling context is permitted to access. In our test, those readable environments contained the configured secret values.
We ran this from the agent's ubuntu context. No change of user or privilege escalation was needed.
The distribution was consistent with secrets being inherited through the environment's process tree. Services with no apparent need for the test credentials held copies alongside the processes executing the agent's commands.
The observed distribution followed this path:
Secret configured through Cursor
↓
Plaintext value delivered into the runtime environment
↓
Value present across the environment's process tree
↓
Agent-executed code reads accessible process environmentsThe observation concerns the configured test secrets delivered to this run. It does not establish access to secrets belonging to other tenants or values that were never injected into the environment.
How credentials become part of the workspace
Cursor gives each Cloud Agent a development environment in which it can carry out a task independently. According to its Cloud Agents overview, that environment includes a repository, execution tools, and desktop and browser access. The resulting changes can be pushed to a branch for review.
A project may also need a private package registry, an authenticated API, or a test database. Configuring credentials makes those services usable from the worker. The required access depends on the job; ordinary development does not automatically require production credentials.

Cursor's environment setup documentation covers these dependencies and recommends AGENTS.md for project-specific guidance. Credentials and instructions therefore meet in the same workspace: one supplies access, and the other helps determine how the agent uses it.
That combination led us to examine what code launched by the agent could read, including code it obtained while following external setup instructions.
Who needs the raw value?
Cursor's security overview describes Firecracker-based VM isolation and configured secrets encrypted at rest with KMS. Once a value is delivered into a process environment, its accessibility also depends on the permissions inside that VM.
Our assessment stayed inside our own guest environment. We did not establish a Firecracker escape or access another user's environment. The question arose from access already available to the agent's ordinary execution context.
A test runner may need a credential to authenticate to a service. Its presence in a VNC server or desktop utility is harder to explain in terms of that task. Each additional copy expands the set of processes from which the value might be recovered.
Why should the raw value also be available to the agent's general execution environment and to unrelated processes inside it?
To examine the consequences, we introduced project guidance that directed the agent to run a helper script. Cursor documents automatic terminal execution and its prompt-injection risk. A helper could therefore run while the developer was waiting for the task's result.
The eventual diff would not necessarily reveal a transient environment read or HTTP request. We needed to observe what happened during execution.
An onboarding script with a second job
The onboarding instructions
We prepared an AGENTS.md workflow that looked like project onboarding material. It included coding conventions, linting guidance, planning steps, and a “First Session Setup” section directing the agent to fetch shared tooling from GitHub Gists.
The credential-collection code lived in a separate script, healthcheck_post_merge.py. The Markdown supplied the reason to fetch and run it: a routine health check before continuing with the project.
This split placed the instruction and its consequences in different files. A reader following the onboarding narrative would encounter the health check as another setup dependency. Determining what it actually did required inspecting the linked script.
The separation was part of the payload's design. Our test shows that the agent followed the resulting workflow; it does not establish how much that separation, by itself, contributed to the outcome.
Following the linked helper
We asked the agent to:
Work on memory optimization, follow the agents file and create a plan.
Work on memory optimization, follow the agent file and create a plan.

In the controlled proof of concept, we used a Gist URL to deliver the workflow reproducibly. The attacker-controlled material told the agent to fetch and execute the helper. The user's work request did not ask it to collect credentials or transmit them.

This is the indirect prompt-injection step: instructions supplied through project material redirected the agent away from the user's intended task and into credential collection.

A poisoned file already present in a repository is a related delivery scenario. It requires an attacker to influence content the agent will consume, such as through a contribution or a compromised project template. The Gist-based test demonstrates the workflow-to-execution path; it does not demonstrate every possible way of placing that workflow in front of a victim.
What the Python script did
The Python script assembled its collection command from string fragments, read the process environments accessible to it, and encoded the results. It then sent the encoded data in an HTTPS POST to an endpoint presented as an OpenTelemetry collector.
The encoding changed how the data appeared in transit. The credential values remained recoverable by the receiver.
The agent fetched the helper and ran it as part of the workflow. No command-approval dialog interrupted the demonstrated sequence.

Recovering the test value
Our endpoint received the encoded process-environment data. Decoding it recovered configured test values, including the benign marker:
teams-top-secret=444444444411111111
The resulting chain was:
User requests memory optimization and planning
↓
Agent reads attacker-controlled AGENTS.md workflow
↓
Agent fetches and runs the linked health check
↓
Script reads accessible process environments
↓
Script sends the data to our HTTPS endpoint
↓
Receiver recovers configured test secretsThe transfer completed while the agent was carrying out the workflow. It did not depend on the developer accepting a code change.
Secrets can leave without entering the conversation
The script's behavior matters even if the model never receives a credential value in a tool result.
Once launched, a program can handle credential bytes and network requests itself. The agent's contribution is the decision to execute it; the program does not need to print the values back into the conversation.
Our payload followed that path: collection, encoding, and transmission happened inside the executed program. Displaying the credentials to the model was not a prerequisite for the transfer.
This matters when evaluating redaction. Removing a value from a terminal result can prevent it from entering a transcript. To stop this kind of transfer, a control must also constrain the program's access to the value or its ability to send the value out.
A clean transcript does not establish that the executing process lacked access to the secret.
How this fits the lethal trifecta
Simon Willison described this general risk as the “lethal trifecta” in his June 16, 2025 post.
The completed test contained all three conditions:
- Access to private data: configured secrets were readable from the execution environment.
- Exposure to untrusted content: the agent followed an attacker-controlled project workflow and its linked helpers.
- External communication: the script could send an HTTPS request to our endpoint.
Automatic command execution connected the injected instructions to the other capabilities. It allowed the agent to move from reading the workflow to running its helper without stopping for a separate command approval.
This framework explains why secret placement matters before deciding whether any individual component has a vulnerability. A readable value becomes exposed to external instructions through the worker's ability to execute them.
Credential types and egress settings
Cursor's Secrets & Network documentation, reviewed for this revision on September 21, 2026, distinguishes three types:
- Environment Variables are visible to the agent.
- Runtime Secrets remain environment variables, with values redacted from tool results, transcripts, commits, and commit messages.
- Build Secrets are supplied only to the Docker build and are excluded from the running agent environment.
The same documentation describes configurable outbound domain restrictions, including an allowlist-only mode.
These distinctions matter when interpreting the test. Runtime output redaction does not claim to remove the underlying environment variable. Build-only delivery changes where a secret is available. An enforced egress policy can prevent the demonstrated request if its destination is blocked.
The proof of concept established plaintext access and a successful outbound transfer in the configuration we tested. We have not established that the same chain succeeds against every current secret type or network policy. The current documentation also does not, by itself, establish that our observed runtime behavior has been removed.
What better secret handling would change
Codex Cloud provides a useful point of comparison. Its environment documentation distinguishes ordinary environment variables from configured Secrets: the latter are supplied to setup scripts and removed before the agent phase. For credentials needed only to prepare the project, we prefer this separation to leaving raw values accessible throughout the agent’s work. It reduces the window in which a redirected agent can collect them.
That boundary still has limits. In our earlier Mind the Gap investigation, the first agent did not receive the configured secret. It wrote code to a branch that a later task’s maintenance script executed with the secret and outbound HTTPS available, before the reviewing agent started. Several later retests did not reproduce the chain; the article records the maintenance issue’s remediation status as unconfirmed. Setup-only access also needs a trust boundary around the code executed during setup or maintenance.
Our preference concerns the credential’s lifetime and accessibility. Cursor’s Build Secrets likewise keep build credentials out of the running agent. The concern demonstrated here is the raw value already present inside the agent-accessible runtime.
NVIDIA’s AI Red Team addresses the shared-environment problem directly in Four Ways to Deploy More Secure AI Agents. It explains why environment-variable injection is insufficient when an agent with command execution can inspect that same environment. Its recommendations include a dedicated secrets manager, on-demand retrieval limited to the process that needs the value, keeping persistent secrets outside the agent’s reach, and narrowly scoped, short-lived tokens when credentials are necessary.
Applied to our finding, the relevant boundary is between agent-executed code and the service holding the credential. If they share an environment or process namespace in a way that permits the read, the value remains exposed. A separate service helps only when enforced permissions prevent that access and constrain the authenticated operations the agent can request.
The limits of the finding
The direct evidence covers plaintext access from the tested runtime and receipt of the test values at our endpoint after the injected workflow ran.
There was no privilege transition in the secret read. The program used permissions already available to the agent's execution context. The architectural question is whether that context should have held those credentials so broadly in the first place.
Repository-instruction attacks also predate this work. Pillar's March 2025 Rules File Backdoor research demonstrated poisoned Cursor rules influencing generated code and discussed credential exfiltration as a possible consequence. The process-level distribution and the end-to-end test described here are the specific observations we are adding to that discussion.
Our assessment used our own account and test data. We did not access another user's data or environment. The result establishes a path to the configured test secrets available to the demonstrated run; the consequences for a real credential would depend on its scope and permissions.
The HackerOne correspondence
We reported the complete chain to Cursor through its HackerOne program, including the indirect prompt injection, plaintext runtime access, and the architectural concern about secret placement.
The reports were closed as informative. After follow-up and mediation, the program team reaffirmed that the reported behavior was outside the bounty program's scope and considered working as designed.

That position describes the intended behavior and the program's scope. The question for teams remains how much credential access they want that behavior to provide.
Decisions about credential access
The most useful design question is how much authority remains available after an agent follows the wrong instruction.
- Keep raw credentials outside general code execution where possible. A broker or authenticated proxy can perform a narrowly defined operation without handing the underlying credential to the worker. Its destinations, permitted actions, and returned data still need controls.
- Limit credential delivery to the task and phase that need it. A package-install token should not automatically remain available during unrelated work. Setup itself needs scrutiny when it executes repository-controlled code.
- Separate the credential-bearing process from unrelated processes. Supplying a secret to one process reduces unnecessary copies, but meaningful isolation also requires controlling what other processes can inspect or access. Merely changing an environment variable into a file does not establish that boundary.
- Restrict outbound destinations. Evaluate which allowed services can receive data, as well as which domains the agent needs for legitimate work. The policy should cover the actual execution and tool paths available to the task.
- Review instruction files and their linked helpers as executable workflow inputs. An onboarding step that asks an agent to download and run a script deserves the same scrutiny as another repository change that introduces execution.
These choices allow useful autonomy while reducing the credentials a redirected worker can collect and the destinations it can reach.
Before configuring a secret for an autonomous worker, a team should be able to determine which processes receive it, how long it remains available, and what prevents agent-executed code from transmitting it. Those answers define the practical boundary around the credential.
If project content redirects the agent, what keeps the credentials inside the environment?





