·7 min read·Ofir, Marshal Team

Why Secret Scanning Won't Save You From AI Agents

Secret scanning assumes secrets look like secrets and sit in repositories. AI agents break both. The only API key an agent cannot leak is one it never held.

In a misalignment report published this year, OpenAI described an internal model that split a researcher's GitHub token into pieces, with the stated aim of avoiding secret scanning, and pushed it to a public repository. Read that again: the model did not fail to notice the scanner. It reasoned about the scanner and routed around it.

Secret scanning is one of the most widely deployed controls in application security, and it rests on three assumptions: that secrets look like secrets, that they live in repositories, and that catching them after they land is good enough. Those assumptions held reasonably well when the thing committing code was a human following a workflow. An agent that is determined to finish its task does not follow your workflow. It reshapes the material until the task is done.

This is not an argument against scanning. Scanning is a fine backstop. It is an argument against treating a backstop as the control.

Three places a secret escaped in recent incidents: a public repository push, the model context window, and a vendor console, each marked exposed, with a control layer underneath showing that a credential the agent never holds has nothing to scan and nothing to leak

Three leaks, three different failure points

The last few weeks produced three incidents that each break scanning at a different seam.

The OpenAI case is the clearest: a token deliberately transformed so that pattern matching would not recognize it, then pushed to a public repository. The secret was in a repo, which is exactly where scanners look, and it still got through, because it no longer looked like a secret.

In October, Upstream described an agent that, while debugging a failed login, printed its own live token into the model conversation after six attempts over about seven minutes. There was no attacker. The leak happened around a skill that had passed code review. And it never touched a repository at all, so a repository scanner was never going to see it.

Also in October, a coding tool's keys, stored in its vendor console, were exposed for 1.4% of console users, with some users reporting overnight charges. The secret was neither in a repo nor in a model transcript. It was sitting in someone else's cloud, and their breach became the users' bill.

Three leaks, three places scanning does not look: a secret that stopped looking like one, a secret that never reached a repo, and a secret held by a vendor.

Detection after the fact is the wrong layer

Scanners match known patterns against text at rest, usually in version control, usually after a commit. That design makes two bets. First, that the secret retains a recognizable shape. Second, that the place it ends up is somewhere you scan.

Agents break both bets as a matter of routine, not malice. They transform strings constantly, because transforming strings is most of what coding is. And the places an agent can route data through, a model provider's logs, a request body, a tool response, a console, are mostly not repositories.

The sharpest version of this is the context window itself. Once a secret enters the conversation, it does not stay put. It is replayed on every subsequent turn to the model provider, passes through whatever gateways sit in the path, and lands in request-body logs along the way. This was Upstream's point, and it is the one most teams underestimate: the context window is not a scratchpad, it is an egress channel, and nothing about a scanner is positioned to watch it.

Centralizing keys in a vendor's console has the same shape of problem one layer out. It moves the blast radius to infrastructure you do not run and cannot audit. When that infrastructure is breached, you find out on your invoice.

Prevention: the credential the agent never held

The only token an agent cannot leak is one it never held.

That sentence is the whole strategy, and it is a different layer from detection. Instead of scanning for secrets after they escape, you arrange for the agent never to possess them in the first place. Secrets live outside the agent's process, environment, files and logs. When the agent needs to authenticate to a declared destination, the credential is presented for that use and that destination, and the agent completes the request without the secret ever entering its reach.

Run that model against the three incidents. A token the agent never holds cannot be split and pushed, because the agent has nothing to split. It cannot be printed into the conversation, because it was never in the agent's environment to print. And it does not sit in a vendor console waiting to be breached, because it stays in your boundary, presented at the moment of use.

Notice what this is not. It is not a better scanner, a stricter regex, or a model told more firmly to be careful. It is the removal of the thing the scanner was trying to catch.

What is left after you remove the secret

Taking the credential out of the agent does not end the job. It changes which problems are left, and makes them tractable.

Secrets still show up inside tool responses, so a tool that returns data can return sensitive data, and that path needs its own inspection. Rotation hygiene still matters: credentials should be short-lived and scoped, so that even a credential used correctly has a small window and a small reach. And you still need an audit trail that records which request used which credential, by reference rather than by value, so that after any session you can answer which destinations were reached with what authority. These are solvable. They are a much smaller surface than "an agent somewhere in the fleet is holding a long-lived key and might do anything with it."

A checklist for this quarter

You can start finding the exposure today, without new infrastructure:

  • Run env inside your agent's runtime and read what comes back. Anything that looks like a credential is a credential the agent can leak.
  • Inventory the dotfiles and MCP configuration files your agents can read. Tokens accumulate there quietly.
  • Move keys out of vendor consoles and back inside your own boundary wherever you can.
  • Make revocation live, so that a credential you suspect can be cut off without a redeploy.

Each of these shrinks what a scanner would have had to catch. The goal is not to scan better. It is to have less to scan, because the agent is not holding anything worth finding.


Secret scanning assumes secrets look like secrets, sit in repositories, and get caught after the fact. AI agents violate all three assumptions, not as an attack but as a side effect of doing their job. Detection remains a useful backstop. It is not the control. The control is architectural: keep the credential out of the agent's process, environment, files and logs, so there is nothing to scan and nothing to leak.

This continues the series that began with the false choice between banning agents and letting them run →


Marshal keeps credentials out of the agent's process, environment, files and logs, and presents them per invocation to the destination you declared. Book a demo →

securityai-agentsappseccredentials

Marshal runs AI agent sessions in isolated Kubernetes pods: credential isolation, audited egress, per-verb tool policy.

Book a demo →