Coding agents keep a local history of each session. That history is useful: you can resume yesterday's work, see which tools ran, and debug a failure. It is also a second home for secrets.
I wrote a small local CLI, agent-secrets, that scans those files, prints a masked report, and can redact what it finds. This article walks through where the files live, what a scan looks like, and how to put a check in front of a commit. It uses only facts I could check, including a run of the tool against its own synthetic fixtures.
Two public reports, two surfaces
On 28 October 2026, Backslash Security published research on session history in Claude Code, Cursor and Codex. They looked at how secrets first entered a session. About three in four came from the agent's own work, mostly tool output such as a file read or a command. About one in ten was typed or pasted by the user. In a lab test, an agent given a normal debugging task read a project's .env on its own. Nobody pasted the key. The session kept it.
They also showed why a guard on .env is not enough. A skill that asked to read .env was blocked. A skill that asked only to write a weekly report from recent session transcripts was allowed through, and the keys came along inside those files.
On 9 November 2026, iTnews reported Apiiro's findings on public GitHub. Claude Code asks before it runs most shell commands. If you pick "Yes, and don't ask again", that choice can be stored as a rule in .claude/settings.local.json. When the rule records the exact command, any secret typed into the command is stored with it.
Apiiro's search found 104,185 copies of that settings file in 103,617 public repositories. Of those, 1,122 held at least one real secret, 1,379 distinct secrets in all. Adding older versions of the file, a shared settings file that teams commit deliberately, and saved agent chat transcripts, the tally reached 2,539 secrets across 1,994 repositories. Apiiro did not test whether the credentials still worked. One organisation they notified confirmed its key had been live.
Anthropic's Boris Cherny, quoted in that article, said Claude Code has historically not done secret scrubbing, and that the team was looking at auto mode and basic secret scanning. He also noted that Claude Code gitignores the settings file on creation, so the public copies had been checked in. Of the 1,122 files with a secret, gitleaks flagged 564 and TruffleHog 643, while 215 slipped past both. The file also sits on the developer machine as plain JSON.
Where the files are
Paths can change with the agent and the version. These are the defaults the CLI uses, and they match what the vendors or the reports describe.
Claude Code stores conversation transcripts as JSONL under $CLAUDE_CONFIG_DIR/projects/ (default ~/.claude). Official documentation says those files are plaintext, and that anything which passes through a tool, including file contents and command output, is written to the transcript: Explore the .claude directory. The tool also reads settings*.json there and ./.claude/settings*.json. It does not read ~/.claude.json.
Codex CLI transcripts are rollout-*.jsonl files under $CODEX_HOME/sessions/YYYY/MM/DD/, directly under $CODEX_HOME/sessions/, and under $CODEX_HOME/archived_sessions/. $CODEX_HOME defaults to ~/.codex.
Cursor support is experimental. The tool reads JSONL files under $CURSOR_CONFIG_DIR/projects/ (default ~/.cursor) when the path contains agent-transcripts. It does not read state.vscdb or ~/.cursor/chats. Backslash described a SQLite store under ~/.cursor/chats/. Those are different layouts, and Cursor changes them, so a clean result in one place is not proof about the other.
If you pass a path, the tool walks it for .jsonl, .json, .txt, .log, .md, .yaml, and .yml. .bak files are skipped unless you name the backup itself. Files larger than 32 MiB are skipped.
Install and a first scan
The package on PyPI is agent-transcript-secrets and the command it installs is agent-secrets:
pipx install agent-transcript-secrets
From a specific GitHub commit, use pipx install "git+https://github.com/kamilkaczmareksolutions/agent-transcript-secrets.git".
With no path, scan uses the default locations that exist on the machine:
agent-secrets scan
The repo ships synthetic fixtures in examples/. Every token there contains FAKE or EXAMPLE, and the shapes are wrong for GitHub secret scanning. I ran the tool on that tree. It exited with status 1 (findings exist) and printed:
file line type preview
--------------------------------------------------------------- ---- ----------------------- -----------------
examples/.claude/projects/-tmp-demo/session.jsonl 1 openai-api-key sk-…ENAI
examples/.claude/projects/-tmp-demo/session.jsonl 2 github-token gho_…OKEN
examples/.claude/projects/-tmp-demo/session.jsonl 2 github-token ghp_…OKEN
examples/.claude/projects/-tmp-demo/session.jsonl 2 github-token github_pat_…OKEN
examples/.claude/projects/-tmp-demo/session.jsonl 3 url-password …
examples/.claude/settings.local.json 4 bearer-token FAK…KEN
examples/.claude/settings.local.json 5 anthropic-api-key sk-ant-…EKEY
examples/.claude/settings.local.json 6 aws-access-key AKIA…EY12
examples/codex/sessions/2026/11/09/rollout-demo.jsonl 2 google-api-key AIza…MPLE
examples/codex/sessions/2026/11/09/rollout-demo.jsonl 2 slack-token xoxb-…OKEN
examples/codex/sessions/2026/11/09/rollout-demo.jsonl 2 stripe-live-key sk_live_…MPLE
examples/codex/sessions/2026/11/09/rollout-demo.jsonl 2 xai-api-key xai-…EKEY
examples/cursor/projects/demo/agent-transcripts/sess/sess.jsonl 1 high-entropy-assignment not…E99
examples/cursor/projects/demo/agent-transcripts/sess/sess.jsonl 1 private-key -----BEGIN …-----
14 secrets found.
The tool never prints the full secret. --json emits the same findings as structured data, with a source field (claude, claude-settings, codex, and so on) and an experimental flag.
The fixtures also include examples/clean/placeholders.json with allowlisted values such as sk-xxx. A scan reports nothing in that file.
Redact, then look at the backup
redact --dry-run shows the replacement and writes nothing. On the same fixtures it printed 14 lines of the form path:line kind preview -> [REDACTED:kind], then 14 secrets would be redacted.
Without --dry-run, redact copies each file to a .bak beside it, then replaces each finding with a [REDACTED:<kind>] token. The .bak file still holds the secret. Delete that copy after you check the redacted file, and do not commit it.
Exit status is 1 when findings exist, 0 when the tree is clean, and 2 for a missing path, a bad flag, or a hook installed outside a git repository.
Put a check in front of the commit
Two hooks exist.
The repo ships .pre-commit-hooks.yaml for the pre-commit framework. Pin rev to a tag:
repos:
- repo: https://github.com/kamilkaczmareksolutions/agent-transcript-secrets
rev: v0.1.0
hooks:
- id: agent-secrets
agent-secrets install-hook writes a git pre-commit hook that runs agent-secrets scan --staged on staged transcript and settings files. A secret blocks the commit. Running it again replaces that block and leaves the rest of an existing hook in place.
Neither hook rewrites git history. If a settings file or a transcript was already pushed, rotate the key. Removing the file from the working tree does not remove it from history, forks, or clones.
What it looks for, and what it misses
Detectors are regular expressions for common key shapes, plus an entropy check on assignments whose names end in key, token, password, or secret. The shapes covered today include OpenAI (sk-), Anthropic (sk-ant-), GitHub (ghp_, gho_, github_pat_), AWS (AKIA), Slack (xox), Stripe (sk_live_), Google (AIza), PEM private-key banners, Bearer tokens, and URLs that embed a password. An xAI rule for the xai- prefix is marked experimental.
A vendor format the patterns do not name can pass unseen. A long random-looking placeholder can be flagged. The tool does not rotate a key, scan other people's repositories, or talk to the network. A clean scan does not prove a secret never left the machine. If a key reached a remote repository, rotate it first, then clean the local copies.
The project is MIT, has no runtime dependencies, and lives at github.com/kamilkaczmareksolutions/agent-transcript-secrets.
Top comments (1)
The dangerous part is not only a secret committed to Git but copied into agent context, logs, patches, and tool transcripts. A useful remediation sequence is revoke first, then search history and artifact stores, then add pre-commit and CI scanning plus least-privilege test credentials so the same workflow has a safer default.