forked from bchanot/claude
`make scan-secrets` flagged 4 generic-api-key hits in ~/.claude, all written by Claude Code itself: roster.json's rendezvousSock/ptySock unix-socket paths and sessionId UUID (long, high-entropy, not credentials), and two per-worker session keys (0600). Same class as the ide/*.lock entry above — machine-local, ephemeral, and unreachable from a commit: link.sh exposes exactly seven repo symlinks under ~/.claude and neither daemon/ nor sessions/ is among them, so `git ls-files` can never see them. Left unfixed they would redden every sweep, which is the failure mode the .env entry already argues against — a permanently red scan stops being read. Scoped to the two exact filenames rather than the directories, and verified: fake secrets planted beside them in the same dirs are still caught, and the repo's own history stays clean (745 commits, no leaks).
104 lines
4.8 KiB
TOML
104 lines
4.8 KiB
TOML
title = "claude-config gitleaks config"
|
|
|
|
# Backstop scanner (job7): pre-commit hook (lib/gitflow.sh emit-hook) and
|
|
# `make scan-secrets`. Extends gitleaks' default ruleset — never replaces it.
|
|
[extend]
|
|
useDefault = true
|
|
|
|
# 3 false-positive classes identified in job7 triage (.audit/job7/ALL-REDACTED.json),
|
|
# each verified empirically against the real flagged files before being added
|
|
# here (see .audit/job7-report.md). None of these are live secrets.
|
|
[[allowlists]]
|
|
description = "job7 triage — known false positives, not secrets"
|
|
|
|
# Content-based: git-game repo test fixtures (#5/#6 in the triage), confirmed
|
|
# synthetic by the repo owner — literal "test-secret-<digits>" values used in
|
|
# unit tests, flagged by the generic-api-key rule on entropy alone.
|
|
regexTarget = "match"
|
|
regexes = [
|
|
'''test-secret-[0-9-]+''',
|
|
]
|
|
|
|
# Path-based: third-party/vendored files outside our control, flagged by
|
|
# rules that don't apply to their content.
|
|
paths = [
|
|
# Official claude-plugins marketplace catalog — 40-char hex "sha" (git
|
|
# commit references, not credentials) trip the sourcegraph-access-token
|
|
# rule, which matches on bare hex length/entropy alone.
|
|
'''plugins/marketplaces/.*marketplace\.json$''',
|
|
# superpowers plugin test fixture — a base64-encoded WS protocol test
|
|
# nonce, not a credential, trips generic-api-key on entropy.
|
|
'''tests/brainstorm-server/ws-protocol\.test\.js$''',
|
|
# NOT a job7 false positive — this IS a real secret, by design: the
|
|
# canonical vault (BDR-026). `make scan-secrets` scans ~/.claude looking
|
|
# for stray COPIES of secrets outside this file; flagging the vault
|
|
# itself on every run is pure noise, not signal.
|
|
'''(^|/)\.env$''',
|
|
# seo-data OAuth token store — legitimate local secret (like ~/.claude/.env),
|
|
# 0600, outside git. Allowlisted so `make scan-secrets` doesn't flag the vault.
|
|
'''(^|/)\.claude/seo-data/tokens\.json$''',
|
|
]
|
|
|
|
# ── secrets-triage 2026-07-14 — 4 FP classes, each verified empirically
|
|
# (unredacted re-scan piped in-memory, values masked; see
|
|
# .gstack/security-reports/2026-07-14-secrets-triage.json). None are secrets.
|
|
# Transcripts and file-history are deliberately NOT path-allowlisted — that is
|
|
# where real leaks land (BDR-057).
|
|
|
|
# Bare 40-hex = git commit SHA (plugin-catalog pins, commit refs quoted in
|
|
# transcripts) tripping sourcegraph-access-token, which matches naked hex.
|
|
# Real sourcegraph tokens keep their sgp_ prefix → still detected.
|
|
[[allowlists]]
|
|
description = "bare 40-hex git commit SHAs (sourcegraph-access-token misfire)"
|
|
regexTarget = "secret"
|
|
regexes = ['''^[0-9a-f]{40}$''']
|
|
|
|
# Synthetic AWS key fabricated by lib/gitflow-test.sh:240 to exercise the
|
|
# pre-commit secret guard; test output lands in session transcripts.
|
|
[[allowlists]]
|
|
description = "gitflow-test synthetic AWS fixture (deliberately fake)"
|
|
regexTarget = "secret"
|
|
regexes = ['''AKIAGDR5XRBXYARW2I5N''']
|
|
|
|
# Public-by-design or expired URL credentials + documentation placeholders.
|
|
[[allowlists]]
|
|
description = "presigned-URL key ids, GitHub image JWTs, doc placeholders"
|
|
regexTarget = "line"
|
|
regexes = [
|
|
'''X-Amz-Credential=AKIA[0-9A-Z]{16}''',
|
|
'''private-user-images\.githubusercontent\.com/[^"]*\?jwt=''',
|
|
'''MAGIC_API_KEY=abc123''',
|
|
# magic MCP docs example — base64 of "the ..." ASCII sample text.
|
|
'''clientKey = 'dGhlIH[A-Za-z0-9+/=]*'''',
|
|
]
|
|
|
|
# Prose in transcripts near the word "tokens" — dictionary phrases flagged by
|
|
# generic-api-key on entropy alone (e.g. a design discussion of publish/reject
|
|
# token pairs). Exact literals only; transcripts stay fully scanned otherwise.
|
|
[[allowlists]]
|
|
description = "prose false positives in transcripts"
|
|
stopwords = ['''publish/reject''']
|
|
|
|
# Ephemeral machine-local IDE auth locks (rotate per IDE session, never leave
|
|
# the machine).
|
|
[[allowlists]]
|
|
description = "Claude Code IDE lock files"
|
|
paths = ['''(^|/)ide/[0-9]+\.lock$''']
|
|
|
|
# ── 2026-09-15 — Claude Code daemon/session runtime state, triaged on macOS.
|
|
# Same class as the IDE locks above: written by Claude Code itself, machine-
|
|
# local, ephemeral. Verified before allowlisting — roster.json's hits are the
|
|
# rendezvousSock/ptySock unix-socket paths and the sessionId UUID (paths, not
|
|
# credentials); sessions/*.key IS a real per-worker key, but 0600 and outside
|
|
# git. Neither directory is reachable from a commit: link.sh exposes exactly
|
|
# seven repo symlinks under ~/.claude (CLAUDE.md, settings.json, hooks, agents,
|
|
# skills, lib, templates) and these are not among them, so `git ls-files` can
|
|
# never see them. Scoped to the two exact filenames, NOT to the directories —
|
|
# a stray copy landing beside them stays detected.
|
|
[[allowlists]]
|
|
description = "Claude Code daemon roster + per-session keys (machine-local runtime state)"
|
|
paths = [
|
|
'''(^|/)\.claude/daemon/roster\.json$''',
|
|
'''(^|/)\.claude/sessions/[0-9]+\.[0-9a-f]{64}\.key$''',
|
|
]
|