Skip to main content
BlogSecurity

GitGuardian Secrets Sprawl 2026: AI Agent Commits, MCP Configs

GitGuardian counted about 29 million new public secrets in 2025 and 24,008 inside MCP configs. What the numbers prove, and a plan to scan developer endpoints.

Matthews Wong

Software Engineer

October 202612 min read
GitGuardian Secrets Sprawl 2026: AI Agent Commits, MCP Configs

Key Takeaway

GitGuardian's 2026 report counts about 29 million new secrets on public GitHub in 2025 and says Claude Code co-authored commits leak at roughly twice the baseline, without proving causation. The practical response is scanning developer machines, not only repositories: MCP configs, agent logs and shell history, then replacing inline tokens with environment references or OAuth.

I read GitGuardian's State of Secrets Sprawl 2026 expecting one clean headline and found three documents that do not quite agree with each other. The report page says Claude Code co-authored commits leak secrets at about twice the baseline. A companion article from the same company says 3.2 percent against 1.5 percent. A third post says 64 percent of 2022 secrets were still not revoked in 2026, while the report chart says 64 percent were still valid.

This post reads those three GitGuardian pages, the Claude Code MCP documentation, and the READMEs of gitleaks and ggshield, and nothing else. Every figure is attributed to the page where I read it, with that page's stated method and limits. Where I did the arithmetic myself I say so. The goal is a plan you can run on a developer laptop this week, and an honest account of what the numbers do and do not justify.

What GitGuardian measured, and what it did not say

The report is the fifth edition of GitGuardian's annual study, published on 17 March 2026 and covering calendar year 2025, with trends back to 2021. Its data sources, as the announcement describes them, are public GitHub commits, internal repositories, collaboration and productivity tools, and MCP configuration files. The table lists the figures this post relies on, where I read each one, and the limit attached to it.

FigureValue as publishedWhere I read itLimit
New secrets on public GitHub, 2025About 29 million, up 34 percent year on yearAnnouncement postApproximate; no sample size or detector list on the page
Public commit growthUp 43 percent year on yearAnnouncement postDifferent denominator from the secret count
AI-service credentials exposed1,275,105, up 81 percentReport page and announcementCounts detections for AI-provider detectors
Claude Code co-authored commitsAbout 2x baseline (report page); 3.2 percent vs 1.5 percent (agent article)Report page and agent articleNo method for spotting AI commits; no causation claimed
Secrets in MCP config files24,008 unique; 2,117 validReport page and agent articlePublic repositories only; validity method not explained
2022 valid secrets still valid64 percent (2023 cohort 66, 2024 cohort 70, 2025 cohort 77)Report page chartDetection-year cohorts; younger cohorts had less time to be fixed

Two limits matter before any figure is quoted. GitGuardian sells secrets-security products, and the announcement itself says leaked secrets may reflect human mistakes and not only AI failures. The report page also states no methodology section: every chart is credited only as data analysis by GitGuardian, so how an AI-assisted commit was identified, or how a baseline was defined, is not something I can tell you.

The Claude Code number is two numbers

The report page puts it as a ratio: Claude Code co-authored commits leak secrets at about twice the baseline across all public GitHub commits. I searched that page for 3.2 percent and it is not there. The 3.2 percent against 1.5 percent pair appears in GitGuardian's later article about agent credentials, which cites the report. Both say the same thing, but only the ratio is on the report page itself, so I quote the ratio first and the pair as the article's reading.

The article states the limit plainly: the comparison does not establish that the tool alone causes the higher rate. I would add two readings of my own. Commits that carry a co-author trailer are a self-selected group, because people who let an agent commit directly may also commit more config and scaffolding, which is where secrets tend to sit. And a rate of 3.2 percent means 96.8 percent of those commits were clean, which is not a case against using the tool.

There is also a scale check worth doing. Secrets grew 34 percent and public commits grew 43 percent. If both counts describe the same public population, the per-commit rate fell by roughly 6 percent (1.34 divided by 1.43), though the page does not say they share a population. The 29 million figure is a record in volume, and I would not read it as a record in rate.

MCP config files are the new .env

GitGuardian found 24,008 unique secrets in MCP configuration files on public repositories. The report page does not give a total of valid ones, but lists the most common valid types: Google API key at 19.2 percent, PostgreSQL connection string at 14 percent, Firecrawl at 11.9 percent, Perplexity at 11.2 percent and Brave Search at 11 percent. The agent article gives 2,117 valid, and my own division puts that at about 8.8 percent of the 24,008. The mechanism is easy to see in the code below.

// Wrong: a literal token in a file that .mcp.json scope shares via git.
// This is the shape GitGuardian counted 24,008 times in public repos.
{
  "mcpServers": {
    "search": {
      "type": "http",
      "url": "https://mcp.example.com/mcp",
      "headers": { "Authorization": "Bearer sk-live-REDACTED-EXAMPLE" }
    }
  }
}

// Right: the file holds only a reference. The value comes from the
// environment of whoever runs Claude Code, so nothing secret is committed.
// Docs: ${VAR} expands in command, args, env, url and headers.
{
  "mcpServers": {
    "search": {
      "type": "http",
      "url": "${SEARCH_MCP_URL:-https://mcp.example.com}/mcp",
      "headers": { "Authorization": "Bearer ${SEARCH_MCP_TOKEN}" }
    }
  }
}

// Check what is unset BEFORE you trust it: an unset variable with no
// default still loads and sends the literal text "${SEARCH_MCP_TOKEN}".
//   claude mcp list

The Claude Code documentation says a project-scoped server lives in .mcp.json at the project root and is shared through version control. That is the design, and it is exactly why an inline token in that file is a commit waiting to happen. The same documentation supports an expansion syntax, so the file can be committed with no secret in it.

Expansion has two traps in the Claude Code documentation. A variable that is unset and has no default does not fail the load: Claude Code warns in claude mcp list and then uses the literal text of the placeholder. And in a remote server url or headers, credential variables such as ANTHROPIC_API_KEY, NPM_TOKEN and HTTPS_PROXY read as empty, so you must copy the value into a variable with your own name.

Where agent credentials sit on a laptop

GitGuardian's agent article is commentary and not a study. It reviews each vendor's documented paths as of September 2026 and does not map temp-file locations. Even so, it gives a useful inventory of places a repository scanner never looks.

ToolPaths the article namesWhat can be in them
Claude CodeProject .mcp.json; user state in ~/.claude/ and ~/.claude.jsonInline MCP tokens; login token in the OS keychain on macOS, but a permission-protected file on Linux and Windows, and on macOS when the keychain is unavailable such as over SSH
Cursor.cursor/mcp.json in the project; ~/.cursor/mcp.json for the userInline tokens as env values or request headers; OAuth and variable references are documented but not enforced
GitHub Copilot CLI~/.copilot/ including mcp-config.jsonlogs, command and session history, session-state, a session-store.db SQLite store, mcp-oauth-config, and a plaintext config.json fallback when no keychain exists
Any MCP serverWherever the client keeps its configEach server can add its own non-human identity and credential

The article adds that credentials get copied into local files for debugging and that logs or prompts can record them. That is the part repository scanning cannot see, and it is why the report's own recommendations include mapping which developer machines hold which secrets.

Where this plan can fail

The first failure is treating a count as exposure. GitGuardian's own page says detected secrets are not the same as exploitable risk, and that prioritisation needs location, usage and downstream consumers. A scanner hit on a laptop in a file with mode 600 is a different problem from the same string in a public repository.

The second is that the scanner becomes the newest place a secret is stored. The gitleaks README describes its redaction option as hiding secrets in logs and stdout. I did not find it saying that report files are redacted, so assume a JSON report contains the secret and write it somewhere private. The third is drift: the agent article itself advises checking vendor docs before writing policy rules, because these paths change often.

The fourth is the one I would worry about most. Revocation lags. The report chart shows 64 percent of valid 2022 secrets still valid four years later. A scanner that finds a secret and a ticket that nobody closes produce the same outcome as no scanner. The report recommends repeatable remediation paths for exactly this reason.

An endpoint scan you can run today

gitleaks documents a dir command that scans a directory or a single file with no git repository, so it works on ~/.claude and on a shell history file. The script below uses only flags I read in its README. I wrote it and did not run it on a corpus, and I could not confirm whether it reads the Copilot SQLite file, so check that on your own machine.

#!/usr/bin/env bash
# endpoint-secrets-scan.sh - scan where agents keep credentials, not just git.
# Uses only flags documented in the gitleaks README (dir, -c, --redact,
# --report-path, --report-format). Exit code 1 means findings by default.
set -u
umask 077                                  # reports may contain the secret itself
OUT="$HOME/.secret-scan-reports"; mkdir -p "$OUT"
CONFIG="$HOME/.gitleaks-endpoint.toml"     # the rule file below

TARGETS=(
  "$HOME/.claude.json"        # Claude Code user state and local-scope MCP servers
  "$HOME/.claude"             # Claude Code state
  "$HOME/.cursor/mcp.json"    # Cursor user-level MCP config
  "$HOME/.copilot"            # Copilot CLI: logs, session history, mcp-config.json
  "$HOME/.zsh_history"        # tokens pasted into commands
  "$HOME/.bash_history"
)

status=0
for target in "${TARGETS[@]}"; do
  [ -e "$target" ] || continue
  gitleaks dir -c "$CONFIG" --redact \
    --report-format json \
    --report-path "$OUT/$(basename "$target").json" \
    "$target" || status=1
done
exit $status
# ~/.gitleaks-endpoint.toml
# Extends the default ruleset (same pattern as the gitleaks README example),
# then adds one rule of my own. The pattern is untested against a real corpus.
[extend]
useDefault = true

[[rules]]
id = "postgres-connection-string"
description = "PostgreSQL URL with an inline password"
regex = '''postgres(?:ql)?://[^:\s/@]+:([^@\s]+)@'''
secretGroup = 1
keywords = ["postgres"]
tags = ["mcp", "database"]

The README says gitleaks exits with code 1 when it finds leaks, and that you can change this with the exit-code flag. The same README says the project is feature complete, takes only security patches and points new work to Betterleaks, so choose the tool with that in mind. The custom rule above extends the default config as the README's own example does, and the PostgreSQL pattern is mine, written because connection strings were the second most common valid type in MCP files.

If you already use GitGuardian, ggshield scans without git too: ggshield secret scan path with the recursive flag, authenticated through ggshield auth login or the GITGUARDIAN_API_KEY variable. Note the cost: it authenticates against GitGuardian's service, as the login and API key setup show, so read its data handling terms before pointing it at home directories.

Fix the source: four ways to keep tokens out of MCP files

Scanning finds leaks and does not stop the next one. The Claude Code documentation offers four ways to run an MCP server without a literal secret in a committed file. They differ in where the secret ends up.

ApproachWhere the secret livesTrade-off
Inline literal in .mcp.jsonIn the file, and in git if the file is committedSimplest; this is the pattern behind the 24,008
Variable reference in .mcp.jsonIn your shell or secret manager environmentUnset variable silently becomes literal text; some credential names read empty in remote url and headers
headersHelper commandWherever your script fetches it fromRuns fresh on every connection with a 10 second timeout and no caching; needs the project trust dialog accepted
OAuth through the mcp commandStored by Claude Code, not in your configNeeds a server that supports it; logout and remove also delete stored tokens

I would pick OAuth where the server offers it, and a headersHelper that reads from a secret manager where it does not. Variable references are the cheapest step and still leave the value in a shell profile, which an endpoint scan will then find.

Commit the .mcp.json only after you grep it for any literal that is not a URL or a variable reference. A pre-commit hook running the same scanner on staged files catches the case where the file was fine yesterday.

What to do on Monday

Five steps, ordered by how much risk each removes per hour of work.

  1. Inventory the agents and MCP servers on each developer machine, which is the first recommendation in the agent article.
  2. Run the scan script on your own laptop first and read the findings before rolling it out, so you know the false positive rate.
  3. Replace inline tokens in project .mcp.json files with variable references, headersHelper or OAuth, then rotate every token the scan found.
  4. Write down who revokes a leaked credential and by when, since revocation lag is the number the report chart puts at 64 percent for 2022.
  5. Treat the leak-rate comparisons as a reason to look, not as a reason to ban a tool, and re-read the sources when GitGuardian updates them.

Whatever you adopt, repeat the check after each vendor release, because the paths and defaults in the articles are dated September 2026.

The defensible reading of GitGuardian's report is narrower than the headlines. Secrets reached a record volume, AI-service credentials grew fastest, MCP config files are a new and common place for tokens, and most old valid secrets are never revoked. Whether agents cause leaks is not shown. What is shown is that the credentials live outside the repository, so the scanner has to run where the agent does.

FAQ

Frequently Asked Questions

Short answers to what readers ask most about this topic.

How many secrets did GitGuardian find on public GitHub in 2025?

GitGuardian's announcement of its 2026 report says about 29 million secrets were newly detected, up 34 percent year on year. The figure is approximate and the page gives no sample size or detector list. It also covers 2025 only, since the report was published on 17 March 2026.

Do Claude Code commits leak more secrets than normal commits?

GitGuardian's report page says Claude Code co-authored commits leak at about twice the baseline across public GitHub. A later GitGuardian article gives 3.2 percent against 1.5 percent. Both state that this does not prove the tool causes the difference, and neither explains how AI-assisted commits were identified.

Why are MCP config files a secrets risk?

Project-scoped MCP servers live in a .mcp.json file that is shared through version control, so an inline token there gets committed. GitGuardian reports 24,008 unique secrets in public MCP configuration files. The fix is to use environment variable references, a headersHelper command or OAuth instead of literal tokens.

Can gitleaks scan a folder that is not a git repository?

Yes. The gitleaks README documents a dir command that scans a directory or a single file with no git history, for example gitleaks dir -v path/to/dir. It exits with code 1 when it finds leaks unless you change the exit code flag.

What happens if an environment variable in .mcp.json is not set?

According to the Claude Code documentation, the config still loads and Claude Code shows a missing-variable warning in claude mcp list and /mcp. It then uses the literal placeholder text. Check that output rather than assuming the server is authenticated.