Secrets Stay Out of Context
Everything the agent reads becomes part of a request to a model, and with a hosted model that request leaves your machine. A key it reads by accident is a key you sent to a third party, wrote into a session log on your disk, and may find hard-coded in the next diff. The fix is not telling the agent where not to look. It is arranging the working tree so that there is nothing secret to find.
This chapter covers only what is new because an agent sits in the loop. Secret stores, scanning and rotation as general practice belong to CyberSecurity Deep Dive, and this page assumes them. What changes with an agent is the number of ways a secret can be read without anyone deciding to read it, and the number of places it goes once it has been.
Where Context Goes
One secret that enters a session can end up in five places. It goes to the provider's servers with every turn that includes it, because the whole context is sent each time, as Chapter 4 described. It may stay in the provider's retention and abuse-monitoring logs for whatever period the plan's terms allow, which is a team policy question for Chapter 13. It sits in the session transcript, which agents commonly keep on your disk so a session can be resumed. It travels with any transcript you share with a colleague. And it can end up in the code itself, if the agent decides to reuse it. Deleting it from one of those places does not reach the others.
Four Ways a Secret Gets In
Reading is the first. The environment file is ignored by git but present on disk, and the ignore file is git's rule, not the agent's. Whatever an agent's search tools skip by default, a plain request to "open the config and check the database settings" usually reads the file by name. Pasting is the second. Kai pastes a stack trace from staging into the session, and the trace contains the staging database connection string, password included. Running is the third. The agent runs a command that prints the environment, or a verbose test that echoes request headers, including the payment provider's key. Committing is the fourth: a key left in a configuration file, or written into the project instructions file as "the test key to use", where every session reads it on start-up.
Notice that none of the four needs a mistake by the agent. Each is the agent doing what it was asked, with a secret in reach. The defence therefore cannot be "tell the agent to be careful". It has to remove the reach.
Keeping Them Out by Construction
Secrets live outside the working tree and are injected into the process at run time from the team's secret store. A file that is not on disk cannot be read, by the agent or by anything else. Configuration names the variable that holds a secret and never contains its value. Development and test keys belong to a sandbox account at the provider, where a leaked key is worth nothing to anyone.
For whatever must remain on disk, the agent's permission settings from Chapter 3 deny reads of secret-file patterns. The difference between that and a sentence in the instructions file is the whole point of this page. A deny rule is enforced by the tool: the read never happens, whatever the model concluded. An instruction is a request the model weighs against everything else in its context, including text written by an attacker, which is the next page's subject. Test the deny rule once, with a request the agent should refuse. A rule nobody has seen refuse anything is an assumption.
Pasted errors need the same treatment by hand. Before a stack trace or a log excerpt enters the session, replace the secret with a placeholder and keep everything else.
pasted: could not connect: postgres://booking:Tr4v3rse-91c@staging-db.internal:5432/booking redacted: could not connect: postgres://booking:<password>@staging-db.internal:5432/booking
What the Agent Does With a Secret It Saw
It uses it. That is not malice; it is helpfulness. Asked to make a failing integration test pass, an agent that has seen the payment sandbox key hard-codes it into a test fixture, because that makes the test pass. It puts a token on a command line, where it lands in shell history. It prints one in a debug line to confirm a connection works. Any string shaped like a credential in a diff is one of Chapter 6's "new and unasked-for" items, and reading the diff is the first line of defence.
The backstop for the one a reader misses is secret scanning, run as a pre-commit hook and again in CI. It does not know what a secret is; it knows what secrets look like, and that is enough for the common cases.
$ git commit -m "refunds: integration test against the payment sandbox" secret scan: staged lines that look like credentials fixtures/payment-sandbox.json:4 commit rejected: move the value to the secret store; rotate it if it was ever real
When One Leaks
Rotate, do not delete. Removing the line from the file, the chat or the history does not un-send it: the copy at the provider, the copy in the local transcript and any shared copy are all still there, and none of them is yours to delete. Rotation is the only response that changes anything, because it makes every copy worthless at once.
At Cragmoor the staging database password from Kai's stack trace is rotated the same afternoon, a twenty-minute job. The same leak of the live payment key would be a much longer day: a production credential, a provider support ticket, a deploy to pick up the new key, and a review of every charge made while the old one was exposed. That difference is why live keys never sit in a working tree where an agent runs, which the last page of this chapter makes into a rule.
Data That Is Not a Key
Member names, email addresses and phone numbers are the same problem with legal weight. A production export used as a test fixture puts thousands of members' personal data into every session that opens the fixture, and from there into every place listed at the top of this page. What personal data may enter a context at all is team policy, Chapter 13's subject, and the default answer is none: test fixtures are synthetic, generated for the tests, with names nobody owns and addresses on a domain reserved for examples.
- "It is in the ignore file, so the agent cannot see it." The ignore file governs what git tracks. Whatever an agent's search skips by default, a request to open the file by name usually reads it.
- "The instructions file tells it never to read secrets." An instruction is a request the model weighs against everything else in context, including text written by an attacker. A deny rule is enforced by the tool and does not depend on the model agreeing.
- "Deleting the key from the chat fixed it." The key was sent with the turn that contained it, and copies exist at the provider and in the local transcript. The only fix that changes anything is rotation.
- "Our plan does not train on our data, so a secret in context is fine." Training is not even one of the five places listed above. The provider's servers and retention logs, the transcript on disk, any shared copy and the next diff all remain.
- "Secrets means API keys." Connection strings, signed URLs, session cookies in a saved browser log and personal data in fixtures are the same problem, and a pasted stack trace is the most common carrier.
- Keep secrets out of the working tree and inject them at run time. A file that is not on disk cannot be read.
- Add deny rules for secret-file patterns, and test them once with a request the agent should refuse. An untested rule is an assumption.
- Redact errors and logs before pasting them: replace the password in a connection string with a placeholder before it enters the session.
- Rotate any credential that entered a context the same day. Removal does not reach the copies already sent.
Knowledge Check
Which everyday action puts a secret into the agent's context without anyone deciding to share one?
- Asking the agent to list the files in the repository's configuration folder by name only
- Running the full unit test suite through the agent while all the tests use synthetic fixtures
- Pasting a staging stack trace whose connection string still contains the database password
- Asking the agent to explain an error message that names a missing environment variable
Why is a deny rule for secret files stronger than a line in the instructions file saying "never read secrets"?
- The tool enforces the rule whatever the model concludes; an instruction is weighed against everything else
- The instructions file is read only at the start of the session, while deny rules are reloaded every turn
- Deny rules encrypt the files they cover, so the agent sees only ciphertext if it ever tries to open one
- Instructions files are limited in length, so long lists of secret file patterns get cut off without warning
Kai realises the staging password went into a session an hour ago. What is the right response?
- Delete the message from the session and clear the local transcript, which removes every copy
- Ask the agent to forget the password and confirm in writing that it no longer holds it in memory
- Rotate the password the same afternoon, which makes every copy, wherever it is, worthless
- Nothing, since staging passwords protect only synthetic data and are not worth the trouble
An agent has read the payment sandbox key earlier in the session. You ask it to make a failing integration test pass. What is the likely result?
- It asks you for the key, because agents never reuse credentials they saw earlier in a session
- It refuses to touch the test, because integration tests that call a payment provider are off limits
- It mocks the provider entirely, since agents always prefer mocks to real keys in tests
- It hard-codes the key it saw into a test fixture, because that makes the test pass
Besides the provider's servers, where does a secret that entered the context end up?
- Only in the provider's training data, if the plan allows the provider to train on customer data
- In retention logs, the session transcript on your disk, any shared transcript, and possibly the code
- Nowhere else, since secrets in a session are discarded once the session has been closed
- In the project instructions file, which agents update automatically with any values they read
You got correct