Scan source trees, staged changes, and AI-agent artifacts.
AI coding agents (Claude Code, Cursor, Codex/VS Code) read and write plaintext config every
session: .claude/, .cursor/, .codex/, and any mcp.json/.mcp.json MCP server config,
which routinely embed real API keys and tokens in env/headers/args fields. An agent can
also paste a real secret straight into a session transcript. credscan includes these paths in its
default scan. Every rule runs over them; the structural mcp-config-secret rule additionally
parses any JSON document with a top-level mcpServers object, whatever its filename.
$ credscan scan .
[1] HIGH Hardcoded secret in MCP server config (mcp-config-secret)
.mcp.json:10 ghp_********************************0a
[2] HIGH AWS access key ID (aws-access-key-id)
src/config.env:12 AKIA**************LE
credscan: 2 finding(s) across 2 file(s).
# This project is not published to PyPI. Install from a checkout:
git clone https://github.com/amasen02/credscan.git && cd credscan
python -m pip install .
credscan scan . # scan a directory (current dir by default)
credscan scan --staged # scan only what's about to be committed
credscan scan --agent-artifacts # scan only .claude/.cursor/.codex/MCP configs/session logsThe distribution metadata is named amasen-credscan; the Python import package and command stay
credscan. That distribution name has not been published, so supported installation is from a
source checkout or a wheel you build locally:
python -m pip install build
python -m build
python -m pip install dist/amasen_credscan-0.1.0-py3-none-any.whldocker build -t credscan .
docker run --rm -v "$PWD":/scan credscan .
docker run --rm -v "$PWD":/scan credscan --agent-artifacts .credscan focuses on files that can contain developer credentials: ordinary source trees, the git
index, and local AI-agent configuration or session artifacts. Its mcp-config-secret rule parses
JSON documents with a top-level mcpServers object and examines literal values in env,
headers, and args fields. Generic rules still scan other agent files, including
.claude/settings.json, .codex/config.toml, and session transcripts.
credscan scan [path] [options]
| Flag | Meaning |
|---|---|
path |
Directory to scan (default: current directory). |
--staged |
Scan the git index (what git commit would actually commit), not the working tree. |
--agent-artifacts |
Scan only AI-agent artifact paths: .claude/, .cursor/, .codex/, any mcp.json, and local session/shell-history logs (.jsonl, .bash_history, .zsh_history, PowerShell history). Combine with --staged to check only staged agent-config changes. |
--json |
Emit machine-readable JSON instead of text — pipe into jq or a CI gate. |
--no-default-excludes |
Walk the excluded directories too (see below). Use it to scan build output, where a bundler can inline a real .env. |
-h, --help |
Show help. |
Exit codes: 0 clean, 1 findings present (CI-friendly — fail the build on it), 2 usage or
filesystem error (not a directory, not a git repo for --staged, etc).
A path scan prunes these directory names anywhere in the tree:
.git node_modules __pycache__ .venv venv .mypy_cache .pytest_cache .tox dist build
dist/ and build/ are included in that list, so a bundler that inlined .env into build output
is not covered by a default run. Whenever a directory is pruned, credscan says so on stderr
(stdout stays clean for --json), and --no-default-excludes scans the whole tree. --staged
scans exactly the staged paths and prunes nothing.
| Rule | Catches |
|---|---|
aws-access-key-id |
AWS access key IDs (AKIA…/ASIA…) |
aws-secret-access-key |
AWS secret keys, in aws_secret_access_key = … context |
gcp-service-account-key |
GCP service-account JSON key files |
private-key-pem |
PEM-encoded private keys (RSA/EC/OpenSSH/DSA/encrypted) |
jwt |
JSON Web Tokens |
github-token |
GitHub tokens (ghp_/gho_/ghu_/ghs_/ghr_/github_pat_) — their near-hex alphabet often lands under the generic entropy threshold, so this needs its own shape rule |
bearer-token |
Bearer <token> headers |
generic-api-key-assignment |
api_key = "…" / client_secret: … style assignments |
generic-high-entropy-string |
Long random-looking tokens no more specific rule already claimed |
mcp-config-secret |
Literal secrets nested in an MCP server config's env/headers/args fields |
- A
.credscanignorefile of path globs (one per line,#comments allowed), checked against every scanned/staged path. - An inline
# credscan:ignoremarker on a line suppresses just that line.
Both are plain, visible, reviewable text. In --staged mode the allowlist is read from the git
index (git show :.credscanignore), so a suppression only takes effect once it is itself staged
and therefore visible in the diff being reviewed; an unstaged or untracked ignore file is reported
on stderr and ignored. A path scan (credscan scan .) has no index to consult and reads the
working-tree file as-is, so when you audit a clean path scan, check whether a .credscanignore is
present and tracked.
pip install -e ".[test]"
ruff check .
pytestThe suite exercises real files in pytest's tmp_path and real throwaway git repositories for
--staged — not mocks — because this tool's entire value proposition is correct filesystem and
git behavior. It covers every detector (true positives, plausible false positives, and
overlap/double-report regressions), the allowlist, redaction, JSON/text rendering, the
--agent-artifacts path filter, and the mcp-config-secret structural parser (valid secrets,
${ENV_VAR} placeholders correctly ignored, malformed JSON handled without crashing).
src/credscan/
cli.py argv -> exit code; wires flags to scanner calls
scanner.py walks a directory or the git index, runs every rule, redacts, sorts
detectors.py line-based regex rules + the generic high-entropy rule (the base engine)
agent_artifacts.py is_agent_artifact_path() + the structural mcp-config-secret rule
entropy.py Shannon entropy + the shared "is this random enough to be a secret" check
allowlist.py .credscanignore + inline `credscan:ignore` marker
redact.py masks a matched secret before it's ever printed
render.py text/JSON output
git_integration.py thin `git` wrapper for --staged (reads the index blob, not the working tree)
models.py Finding / Severity shared types
tests/ one test module per src module, plus CLI end-to-end tests
Contributions are welcome — new detectors, fewer false positives, better docs. See
CONTRIBUTING.md for the workflow and coding bar, and please be mindful of the
Code of Conduct. Use the issue templates; green CI (lint + test) is required
on every pull request. Report security issues privately per SECURITY.md — never
as a public issue.
This project is, and will remain, free and open source. As maintainer I commit to:
- A permissive licence, kept stable. MIT — use it commercially, fork it, build on it. No relicensing of accepted contributions.
- No CLA. Contributions are accepted under the MIT licence; you keep the copyright to your work.
- An honest history. Real, walkable commits — no fabricated activity, no rewritten releases.
- Best-effort, transparent triage. Issues and pull requests are read and answered; security
reports are acknowledged within 72 hours (see
SECURITY.md). - A welcoming community governed by the Code of Conduct.
- Reproducible builds. Green CI — lint, tests, dependency audit, and CodeQL security analysis — on every change.
MIT — see LICENSE. You are free to use, modify, and distribute this software,
including for commercial purposes, provided the copyright notice is retained.
Ama Senevirathne — GitHub
We deliberately built this repository to be 100% open, modular, and easy to fork and extend:
- 🔓 Permissive MIT License: Zero CLA, commercial use permitted, you keep full ownership of your contributions.
- 🛡️ Hardened Supply Chain: Built with automated CI testing, OpenSSF Scorecard supply-chain security, and strict quality checks.
- ⚡ High-Performance Foundation: Zero unnecessary bloat — clean architectural boundaries that make hacking on this code a joy.
- Add detection patterns for OpenAI API keys, Anthropic tokens, and HuggingFace credentials
- Build a pre-commit git hook generator (
credscan install-hook) - Package a zero-dependency standalone binary for Linux / macOS / Windows CI runners
git clone https://github.com/amasen02/credscan.git
cd credscan
pip install -e ".[test]"
pytest- Fork the repo & clone it locally.
- Create your feature branch (
git checkout -b feat/my-awesome-idea). - Verify tests pass cleanly.
- Open a PR — we review and merge PRs within 24–48 hours!
⭐ Found credscan useful? Please star the repository to support continued security engineering!