Coding Agents Are Leaking Your Secrets to GitHub · Apiiro research · November 2026
Approved Claude Code commands are carrying secrets into public repositories
Apiiro, an application security vendor, counted public copies of Claude Code's local permissions file, .claude/settings.local.json. Of 104,185 copies, 1,122 (1.1%) held a real secret. Adding file history, the shared settings.json file and saved agent transcripts, Apiiro reports 2,539 distinct secrets in 1,994 public repositories across 63 organizations, and says one company confirmed its key had been live. Its examples include a database vendor's own cloud API key, a production Azure Postgres password and a Square production token.
Apiiro says the cause is Claude Code's own behavior. When a proposed command carries a secret from a config file and the user picks "Yes, and don't ask again", the exact command, secret included, is saved as a permission rule. Claude Code adds the file to the developer's global git ignore when it creates it inside a repo, but not to the repo's own .gitignore, so a folder that becomes a repo later, a clone on another machine, or an already committed file is not covered. In 539 of the 1,105 repos with a real secret that Apiiro traced, a commit co-authored by Claude changed the file. Apiiro reproduced the behavior with Opus 5.5 and Fable 5.1.
Scanners missed part of it. Gitleaks flagged 564 of the 1,122 files and TruffleHog flagged 643; 215 were flagged by neither, mostly because the secret was a password typed inside a command, such as after PGPASSWORD= or sshpass -p. The figures come from read-only GitHub code search run November 1 to 3. A "real secret" here means a string that matches a provider key format or a password beside a public host. Apiiro did not test any credential, and an LLM reviewer judged the values alongside its rules. The counts have not been independently reproduced.
Why it matters: An agent's record of what it ran is now a place secrets live, and the saved rule is the literal command. For Claude Code users the checks are concrete: search your repositories and their history for .claude/settings.local.json, rotate anything the file ever held, and have commands reference a variable such as $DB_URL so the saved rule holds the name and not the value. Apiiro also recommends approving patterns such as Bash(npm run:*) over literal commands. Because key-format scanners miss passwords inside commands, any harness that stores commands, transcripts or memory files needs its own check for them.