by EZSCAPE
GPU-powered secret scanner. 1179 detectors compiled into a single binary. Scans source trees, git history, stdin, and Docker images.
Built in Rust. Runs on Windows, Linux, and macOS.
Requires Rust 1.80+ and the NVIDIA CUDA toolkit (nvcc on PATH or CUDA_PATH set). The CUDA kernel compiles to PTX at build time. No GPU is needed to run the binary; it falls back to WGPU, SIMD, or CPU at runtime.
git clone https://github.com/edenaion/EZ-SniffKey.git
cd EZ-SniffKey
cargo build --releaseBinary lands at target/release/sniffkey (or sniffkey.exe on Windows).
Copy it somewhere in your PATH:
# Linux/macOS
cp target/release/sniffkey ~/.local/bin/
# Windows (PowerShell)
Copy-Item target\release\sniffkey.exe "$env:USERPROFILE\bin\"sniffkey doctorRuns 7 checks: backend availability, detector load, an end-to-end self-test, and a backend parity test that confirms GPU and CPU produce identical findings.
# Scan current directory
sniffkey scan
# Scan a specific path
sniffkey scan /path/to/repo
# Scan from stdin
echo "AKIAIOSFODNN7EXAMPLE" | sniffkey scan --stdin
# Only high/critical findings
sniffkey scan --severity high
# JSON output
sniffkey scan -f json
# SARIF output (for CI integrations)
sniffkey scan -f sarif -o results.sarifAll detectors compile into the binary at build time. No config files to download or manage. Covers AWS, GCP, Azure, GitHub, GitLab, Slack, Stripe, OpenAI, Anthropic, and 900+ more services.
222 detectors (detectors/gl-*.toml) are ported from gitleaks (MIT License, Copyright (c) 2019 Zachary Rice), including its generic high-entropy detection with stopword allowlists. The engine implements gitleaks rule semantics: capture-group secret extraction, per-rule Shannon entropy thresholds, and allowlist filtering.
Aho-Corasick automaton (18,606 states) uploads to GPU at startup. Prefilters input at GPU speed before regex extraction. The CUDA backend runs a native kernel compiled to PTX at build time. The WGPU backend covers Vulkan, DX12, and Metal. All four backends produce identical findings.
Backend priority: CUDA > WGPU > SIMD > CPU. Falls back automatically. Override with:
SNIFFKEY_BACKEND=cpu sniffkey scanGPU kicks in at 32KB+ inputs. Below that, CPU is faster and used automatically.
On CPU-only hosts (and CI), the SIMD backend runs a memchr-based prefix prescreen (SSE2/AVX2 on x86_64, NEON on aarch64) for the highest-value detectors alongside the Aho-Corasick prefilter. Each prefix contains its detector's keyword, so the result is identical to the plain CPU path, which a parity test enforces.
# Pre-commit: scan staged files only
sniffkey scan --git-staged
# PR review: scan changes since a ref
sniffkey scan --git-diff main
# Full history: scan all blobs across all branches
sniffkey scan --git-historysniffkey scan --incrementalCaches BLAKE3 hashes of scanned files. Skips unchanged files on re-scan.
sniffkey scan --parallelMulti-threaded file processing with rayon.
Finds secrets hidden inside encoded payloads:
☼ Base64-encoded strings
☼ JWT payloads
☼ Kubernetes Secrets (.data fields)
☼ Docker config (~/.docker/config.json auth)
☼ Helm templates and Jinja variables
Catches secrets split across lines:
☼ Backslash line continuation
☼ JavaScript string concatenation
☼ YAML block scalars (| literal, > folded)
Strips zero-width characters, soft hyphens, and bidi overrides before scanning. Catches obfuscation attempts.
Each finding gets a confidence score (0.0 to 1.0) based on:
☼ Shannon entropy of the secret value
☼ Surrounding context (variable names, assignment patterns)
☼ Companion pattern matches (nearby config keys)
☼ Checksum validation (where applicable)
Filter by confidence:
sniffkey scan --min-confidence 0.7☼ Text - Colored terminal output (default)
☼ JSON - Machine-readable, one object per finding. Secret values are redacted unless --show-secrets is passed
☼ SARIF 2.1.0 - For GitHub Advanced Security, VS Code SARIF Viewer, and CI pipelines
| Flag | Effect |
|---|---|
--fast |
Skip decode pipeline and entropy scoring; raises the confidence floor to 0.5 (unless --min-confidence is set) |
--deep |
Maximum detection depth, lower thresholds |
--baseline <file> |
Only report findings not in a previous snapshot |
--show-secrets |
Print unredacted secret values (opt-in) |
--no-ignore |
Scan files normally skipped by .gitignore/.ignore (e.g. .env). --exclude patterns still apply |
--extra-paths <dir> |
Additional directories to scan (gitignore bypassed). Repeatable |
--scan-ai-logs |
Auto-discover and scan AI tool chat histories (.claude/, .codex/, .continue/, .cursor/, .aider/) in scan root and home directory |
Documented vendor example keys and pure placeholders (AKIAIOSFODNN7EXAMPLE,
all-x tokens, the jwt.io specimen) are suppressed by an exact-match fixture
list, so they never show up as findings.
sniffkey hook installThis writes a pre-commit hook to .git/hooks/pre-commit that runs sniffkey scan --git-staged --severity high before each commit. If secrets are found, the commit is blocked.
1. Install sniffkey (see Install above).
2. Install the hook in any repo you want protected:
cd /path/to/your/repo
sniffkey hook install3. Commit as normal. The hook runs automatically:
git add .
git commit -m "Add feature"
# sniffkey scans staged files before the commit completes
# If secrets found: commit blocked, findings printed to stderr
# If clean: commit proceeds normally4. Handle a blocked commit. If sniffkey finds a secret:
CRITICAL aws-access-key src/config.rs:12 AKIA...MPLE confidence=0.85
☼ Remove the secret from the file
☼ Use environment variables or a secrets manager instead
☼ Run sniffkey explain aws-access-key to see rotation instructions
☼ Stage the fix and commit again
5. Suppress false positives (if the finding is not a real secret):
# Add to .sniffkeyignore
echo "detector:generic-secret" >> .sniffkeyignore
# Or report it to calibrate the detector
sniffkey calibrate fp generic-secret6. Remove the hook if needed:
sniffkey hook uninstallIf you already have a pre-commit hook, add this line to it:
sniffkey scan --git-staged --severity high || exit 1Add to .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: sniffkey
name: EZ-SniffKey secret scan
entry: sniffkey scan --git-staged --severity high
language: system
pass_filenames: falseAI coding tools (Claude Code, Codex CLI, Cursor, Continue, Aider) store conversation transcripts on disk. If you paste a secret into a prompt or the AI reads one from your codebase, that secret persists in plaintext in your home directory.
# Scan current repo + all discovered AI tool directories
sniffkey scan --scan-ai-logs
# Scan a specific AI tool directory
sniffkey scan --extra-paths ~/.claude --extra-paths ~/.codex--scan-ai-logs checks for .claude/, .codex/, .continue/, .cursor/, and .aider/ in both the scan root and your home directory. Files found are printed to stderr:
[extra-path] .claude (124 files)
[extra-path] C:\Users\you\.codex (37 files)
Claude Code runs shell commands on specific events. Hooks receive JSON on stdin and control flow with exit codes. Exit 0 allows, exit 2 blocks.
Scans your prompt text before it reaches the AI. If your message contains a secret, the hook blocks submission. The hook reads JSON from stdin, extracts the prompt field, and pipes it through sniffkey.
Save this script somewhere in your PATH (e.g. ~/.local/bin/sniffkey-prompt-gate.sh):
#!/bin/bash
# Extract prompt text from Claude Code hook JSON
prompt=$(jq -r '.prompt // empty')
if [ -z "$prompt" ]; then
exit 0
fi
# Scan the prompt for secrets
echo "$prompt" | sniffkey scan --stdin --severity high --fast >/dev/null 2>&1
rc=$?
if [ "$rc" -eq 1 ]; then
echo "sniffkey: secrets detected in prompt. Remove them before submitting." >&2
exit 2
fi
exit 0Then add to .claude/settings.json (project-level) or ~/.claude/settings.json (global):
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "sniffkey-prompt-gate.sh",
"timeout": 15
}
]
}
]
}
}If sniffkey finds secrets, exit code 2 blocks the prompt and shows the warning. Remove the secret from your message and resubmit.
Scans AI chat transcript directories when Claude Code finishes responding. Reports findings as context that Claude can act on:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "sniffkey scan --scan-ai-logs --severity high --fast -f json 2>/dev/null | head -c 2000",
"timeout": 30
}
]
}
]
}
}The Stop hook exits 0, so Claude sees any findings as context in the conversation. It does not block the session from ending.
For full coverage, use both. The UserPromptSubmit hook prevents you from sending secrets to the AI. The Stop hook catches secrets that were discussed, generated, or read from the codebase during the session.
Schedule a recurring scan of AI tool directories to catch secrets across all projects. This covers tools that do not support hooks.
# Linux/macOS cron (daily at 8am)
0 8 * * * sniffkey scan ~ --scan-ai-logs --severity high -f json -o ~/sniffkey-ai-audit.json
# Windows Task Scheduler (PowerShell)
$action = New-ScheduledTaskAction -Execute "sniffkey" -Argument "scan $env:USERPROFILE --scan-ai-logs --severity high -f json -o $env:USERPROFILE\sniffkey-ai-audit.json"
$trigger = New-ScheduledTaskTrigger -Daily -At 8am
Register-ScheduledTask -TaskName "SniffKey AI Audit" -Action $action -Trigger $trigger# Search detectors by name, ID, or service
sniffkey detectors --search stripe
# List all detectors for a service
sniffkey detectors --service aws --verbose
# Filter by severity
sniffkey detectors --severity critical
# Show full details for a specific detector
sniffkey explain aws-access-keyexplain shows the regex patterns, keywords, companion patterns, and a link to the service's key rotation docs.
# Save a baseline
sniffkey scan -f json -o before.json
# ... make changes ...
# Save current state
sniffkey scan -f json -o after.json
# See what changed
sniffkey diff before.json after.jsonOutput shows NEW findings (introduced since baseline), RESOLVED findings (no longer present), and a count of unchanged findings. Exit code is 1 if new findings exist, 0 if clean.
[scan]
severity = "high"
min_confidence = 0.5
exclude = ["vendor/**", "*.min.js"]
# Disable a detector by id (repeat the table per detector)
[detector.generic-secret]
enabled = falseSuppress findings by hash, detector ID, or path glob:
# By finding hash
hash:abc123...
# By detector
detector:generic-secret
# By path
path:test-fixtures/**
Suppressions support governance metadata for audit trails:
hash:abc123... ; reason="Test fixture" ; expires=2025-12-31 ; approved_by="ed"
detector:generic-secret ; reason="Too noisy for this repo"
Expired suppressions (past the expires date) are automatically ignored.
# Bash
sniffkey completions bash > ~/.local/share/bash-completion/completions/sniffkey
# Zsh
sniffkey completions zsh > ~/.zfunc/_sniffkey
# Fish
sniffkey completions fish > ~/.config/fish/completions/sniffkey.fish
# PowerShell
sniffkey completions powershell > $PROFILE\..\sniffkey.ps1Add this to .github/workflows/secrets.yml in your repo:
name: Secret scan
on: [push, pull_request]
jobs:
sniffkey:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install CUDA toolkit (build-time requirement for the CUDA kernel)
run: sudo apt-get update && sudo apt-get install -y nvidia-cuda-toolkit
- name: Build EZ-SniffKey
run: |
git clone https://github.com/edenaion/EZ-SniffKey.git /tmp/sniffkey
cd /tmp/sniffkey
cargo build --release
cp target/release/sniffkey /usr/local/bin/
- name: Scan for secrets
run: sniffkey scan --severity high -f sarif -o results.sarif
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarifExit code 1 fails the workflow if secrets are found. SARIF upload sends results to GitHub's Security tab. CI runners have no GPU; sniffkey detects CI=true and uses the SIMD/CPU path at runtime.
Any CI that runs shell commands works:
# Install and scan (exit 1 = findings, exit 0 = clean)
sniffkey scan --severity high --parallel| Code | Meaning |
|---|---|
| 0 | Clean scan, no findings |
| 1 | Findings above severity/confidence threshold |
| 2 | User error (bad arguments, invalid config, unknown detector) |
| 3 | System error (scanner compile failure, I/O error, backend crash) |
CI pipelines can rely on these codes to gate deployments.
crates/
core/ Detector types, severity levels, TOML parsing
scanner/ AC prefilter, regex extraction, confidence scoring, GPU backends, decode pipeline
sources/ File walker (gitignore-aware), git sources, stdin reader
cli/ Binary entry point, output formatting, config, suppression
detectors/ 1179 TOML detector definitions (compiled into binary at build time)
Single binary. No runtime dependencies. All detectors baked in at compile time.
| Platform | Backend |
|---|---|
| Windows (x86_64) | CUDA, WGPU (Vulkan/DX12), SIMD, CPU |
| Linux (x86_64) | CUDA, WGPU (Vulkan), SIMD, CPU |
| macOS (ARM/x86_64) | WGPU (Metal), SIMD, CPU |
EZ-SniffKey was inspired by KeyHog. I built my own implementation because I believe security tooling should come from identifiable, accountable people.
MIT
