Skip to content

edenaion/EZ-SniffKey

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EZ-SniffKey

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.


Install

From source

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 --release

Binary 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\"

Verify installation

sniffkey doctor

Runs 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.


Quick start

# 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.sarif

Features

1179 built-in detectors

All 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.

GPU acceleration

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 scan

GPU 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.

Git scanning

# 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-history

Incremental scanning

sniffkey scan --incremental

Caches BLAKE3 hashes of scanned files. Skips unchanged files on re-scan.

Parallel scanning

sniffkey scan --parallel

Multi-threaded file processing with rayon.

Decode-through

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

Multiline reassembly

Catches secrets split across lines:

☼ Backslash line continuation

☼ JavaScript string concatenation

☼ YAML block scalars (| literal, > folded)

Unicode normalization

Strips zero-width characters, soft hyphens, and bidi overrides before scanning. Catches obfuscation attempts.

Confidence scoring

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

Output formats

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

Scan modes

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.


Git pre-commit hook

Quick setup

sniffkey hook install

This 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.

Step-by-step walkthrough

1. Install sniffkey (see Install above).

2. Install the hook in any repo you want protected:

cd /path/to/your/repo
sniffkey hook install

3. 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 normally

4. 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-secret

6. Remove the hook if needed:

sniffkey hook uninstall

Using with existing hooks

If you already have a pre-commit hook, add this line to it:

sniffkey scan --git-staged --severity high || exit 1

Using with the pre-commit framework

Add 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: false

Scanning AI chat histories

AI 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 hooks

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.

UserPromptSubmit hook (pre-send gate)

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 0

Then 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.

Stop hook (post-session audit)

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.

Both hooks together

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.

Periodic sweep (optional)

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

Exploring detectors

# 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-key

explain shows the regex patterns, keywords, companion patterns, and a link to the service's key rotation docs.


Comparing scan results

# 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.json

Output 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.


Configuration

Per-repo config: .sniffkey.toml

[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 = false

Suppression: .sniffkeyignore

Suppress 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.


Shell completions

# 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.ps1

CI integration

GitHub Actions

Add 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.sarif

Exit 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.

Other CI systems

Any CI that runs shell commands works:

# Install and scan (exit 1 = findings, exit 0 = clean)
sniffkey scan --severity high --parallel

Exit codes

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.


Architecture

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.


Supported platforms

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

Why this exists

EZ-SniffKey was inspired by KeyHog. I built my own implementation because I believe security tooling should come from identifiable, accountable people.


License

MIT

About

GPU-powered secret sniffer to help you maintain digital hygiene in an agentic world.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors