Before you click 'don't ask again': what your coding agent saves, and how to keep secrets out of it
On November 5, Apiiro's researchers reported what they found in public GitHub repositories: 104,185 copies of Claude Code's .claude/settings.local.json, and 1,122 of them held a real secret, from database passwords to AW
On November 5, Apiiro's researchers reported what they found in public GitHub repositories: 104,185 copies of Claude Code's .claude/settings.local.json, and 1,122 of them held a real secret, from database passwords to AWS keys. Counting git history and other agent files too, it came to 2,539 distinct secrets across 1,994 repositories (as iTWire reported it).
How the secrets got there is simple. A saved approval is a rule, the rule is the command, and a password typed into the command is saved with it. Here's what each agent saves when you say "don't ask again", and the habits that keep secrets out of it, whichever agent you use.
What each agent saves
Claude Code. "Yes, and don't ask again" on a shell command saves a rule permanently, per repository and command, "to .claude/settings.local.json at the root of the git repository" (Permissions). A rule with no * matches one exact command; for a prefix, the dialog writes a rule such as npm test *. The first time Claude Code writes that file in a repository that doesn't ignore it, it adds **/.claude/settings.local.json to your global git excludes (Settings). That protects your machine, not the repository: a teammate, another laptop or a script that commits everything doesn't have your excludes. /permissions lists every rule and the file it came from.
Codex. Its approval offers "Yes, and don't ask again for commands that start with" a prefix, and "Yes, and don't ask again for this command in this session" (source). The first writes a prefix rule to ~/.codex/rules/default.rules, in your home folder rather than the repository (Rules). Codex calls rules experimental, and asks you to review a suggested prefix carefully before accepting it.
Gemini CLI. It offers "Allow once" and "Allow for this session". "Allow for all future sessions" appears only once you turn on security.enablePermanentToolApproval, which is off by default (Configuration). The saved policy goes to your user policies folder, and for a shell command it's keyed on the program, so approving one npm command can let later ones through too (issue #30195).
The pattern: a session approval ends with the session, and a saved one is a file that outlives the task. Know where yours live.
Seven habits that keep secrets out
-
Never put a secret in a command an agent runs. Not
PGPASSWORD=… psql, notcurl -H "Authorization: Bearer …". An inline variable still puts the value in the command text, which ends up in the saved rule, the transcript and your shell's process list (CWE-214). Let the program read it from a secret manager or a config file instead. -
Deny reads of your secret files. In Claude Code, deny rules hold in every permission mode:
"deny": ["Read(./.env)", "Read(./.env.local)", "Read(./secrets/**)"](Best practices). -
Ignore local settings in the repository itself. Add
.claude/settings.local.jsonto the project's.gitignore, so the rule travels with the repository. If it's already tracked,git rm --cachedit first (GitHub). - Prefer session approvals while you're unsure. You can always save the rule later.
-
Review saved rules now and then:
/permissionsin Claude Code,~/.codex/rules/default.rulesfor Codex, and Gemini CLI's policies folder. - Turn on push protection for the repository. It blocks a push that carries a detected secret, and it's off by default at the repository level (GitHub). Don't rely on scanners alone: in Apiiro's set, Gitleaks and TruffleHog both missed 215 of the files that held a secret.
- If a secret leaked, rotate it first. Rewriting history and force-pushing doesn't reach clones, forks or cached views (GitHub).
The other direction: instruction files you didn't write
Agents read AGENTS.md and CLAUDE.md as instructions, so a file you didn't write can steer one:
- Backslash Security showed Codex following attacker instructions in a project's
AGENTS.md, copying~/.aws/credentials; that payload has since been patched (Backslash). - Forever Security found an
AGENTS.mdplanted in a user's Downloads folder that made the agent rewrite its own configuration, and reproduced it on Codex and Claude Code (Forever Security).
What helps: read the instruction files and the project's agent config in a repository you didn't write before you start an agent in it, and use your agents' folder trust. Codex loads a project's .codex/ layer only when you trust the project (Config), Claude Code holds a tracked settings file's rules until you trust the folder, and Gemini CLI skips an untrusted folder's settings, .env files and MCP servers (Trusted folders). And don't start an agent with no approvals in a repository you've just cloned.
Doing this in Moontors
I build Moontors, a free desktop app that runs Claude Code, Codex, Gemini CLI and Grok Build side by side, so take this part as the maker's view.
- Every ask shows exactly what will run, such as "Run this command?" with the command in a code font, and Allow or Deny.
- Allow for this session adds a rule for that session only. The session's rules are listed in Configuration, under This session, where you can remove one. (Allow for this session)
- A permission mode per session, from Manual, which asks before each edit and command, to Bypass.
- Trust this folder comes last in Create session and Add project, and its ⓘ names some of what the folder's config runs. Leave it off, and the session starts untrusted. Moontors never writes your agents' own trust files. (A folder's trust)
Whatever you use, the rule of thumb is the same: approve for the session, keep secrets out of commands, and treat a saved approval as a file you're responsible for.
AI did the writing, I did the reading, and we both took credit.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.