credential-and-key-scanning

verified

7393a061-a65f-4716-9560-f7dc6919b32f

Scan code and git history for hardcoded secrets (API keys, tokens, passwords) and remove them. Use before committing, in CI, and on any repo handoff.

Metadata

Skill ID
7393a061-a65f-4716-9560-f7dc6919b32f
Version
1
Owner
387274b7-2891-478b-81b8-e11d5adb9319
Tags
secretscredentialsscanninggitleakstrufflehoghardcodedkeys
Signature
verified
Integrity
OK
Content hash
4cc5aa432a0b049cc85ac6aad1281dd052f8e4368ff2b355aef4221ff12192dc
Created
2026-08-15T05:24:22Z

Skill file

Raw skill file (markdown source)
# Credential and Key Scanning

Use when you need to scan a codebase or git history for hardcoded secrets — API keys, tokens, passwords, private keys — before committing, in CI, or during a repo handoff.

## Scanning Tools & Commands

### Gitleaks (recommended for git history)
```bash
# One-shot scan of entire git history
gitleaks detect --source . --verbose

# Scan a specific commit range
gitleaks detect --log-opts="HEAD~50..HEAD"

# Install as pre-commit hook (catches secrets before commit)
gitleaks protect --staged --verbose
```

### TruffleHog (alternative, scans for high-entropy strings)
```bash
# Scan git history
trufflehog git file://. --only-verified

# Scan a specific branch
trufflehog git file://. --branch main --only-verified

# Scan current working directory (filesystem, not just git)
trufflehog filesystem .
```

### Adding to .pre-commit-config.yaml
```yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks
```

## Reading Scan Results

A positive hit returns:
- **Rule ID**: which detector triggered (e.g., `generic-api-key`, `aws-access-key`)
- **Secret**: the matched string (masked in some tools)
- **File + line number** or **commit SHA + line**
- **Entropy**: for TruffleHog, higher entropy = more likely a real secret

### False-Positive Triage Decision Table

| Scenario | Action |
|---|---|
| A known test fixture key (e.g., `test_key_123`) | Add to `.gitleaks.toml` allowlist |
| A hex hash / UUID that looks like a key | Add to allowlist with a comment |
| A real secret deliberately placed | Rotate immediately, then purge (see remediation) |
| Unsure | Treat as real; rotate to be safe |

### Gitleaks allowlist example (`.gitleaks.toml`)
```toml
[allowlist]
  description = "False positives"
  paths = [
    '''test_.*\.py''',
    '''\.md$''',
  ]
  regexes = [
    '''AKIA[0-9A-Z]{16}''',
  ]
```

## Remediation Workflow

1. **ROTATE THE SECRET FIRST** — Assume it's compromised the moment it hit the repo. Revoke it in the provider console (AWS IAM, GitHub tokens, etc.) and generate a new one.
2. **Move the secret** to environment variables, a `.env` file (gitignored), or a secret store (HashiCorp Vault, AWS Secrets Manager, GitHub Secrets).
3. **Purge from git history** (see `secrets-leak-remediation` skill for the full workflow).
4. **Add detection** — update `.gitleaks.toml` to catch this pattern in the future.

## CI Integration

```yaml
# GitHub Actions example
- name: Scan for secrets
  uses: gitleaks/gitleaks-action@v2
  env:
    GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
```

## Which Tool When

| Scenario | Tool |
|---|---|
| Full git history scan on a local repo | `gitleaks detect` |
| Scanning a remote/CI without a full clone | `trufflehog git <url>` |
| High-entropy secrets (no known pattern) | `trufflehog` (entropy-based) |
| Known secret patterns (AWS keys, JWT) | `gitleaks` (rule-based) |
| Pre-commit / pre-push gate | `gitleaks protect --staged` |
| Filesystem scan (not git) | `trufflehog filesystem .` |

Both are complementary — gitleaks is faster with known patterns; trufflehog catches novel high-entropy strings gitleaks misses.

## Common Secret Patterns to Watch For

| Type | Pattern / Indicator |
|---|---|
| AWS Access Key | `AKIA[0-9A-Z]{16}` |
| AWS Secret Key | 40-char base64-ish string near an access key |
| GitHub PAT | `ghp_[A-Za-z0-9]{36}` or `github_pat_...` |
| Stripe key | `sk_live_[0-9a-zA-Z]{24}` |
| Google API key | `AIza[0-9A-Za-z_-]{35}` |
| JWT | `eyJ...` (three dot-separated base64 sections) |
| Private key | `-----BEGIN (RSA |EC )?PRIVATE KEY-----` |
| Connection string | `postgres://user:password@host/db` |

A regex you can drop into gitleaks to catch a custom org pattern:
```toml
[[rules]]
id = "my-org-internal-token"
description = "Internal service token (myorg_ prefix)"
regex = '''myorg_[a-f0-9]{32}'''
```

## Verifying a Scan Actually Ran

A scan that silently fails (binary missing, wrong path, empty target) is a false sense of security:

```bash
# Confirm gitleaks is installed and findable
which gitleaks && gitleaks version

# Confirm the scan actually inspected the repo (non-zero output)
gitleaks detect --source . --report-format json --report-path /tmp/leaks.json
jq 'length' /tmp/leaks.json    # 0 = clean, N = N findings

# Confirm the exit code semantics (gitleaks exits 1 when leaks found)
gitleaks detect --source . >/dev/null 2>&1
echo "exit code: $?"   # 0 = clean, 1 = leaks, other = scan failed
```

**A scan that errored out is NOT a clean scan.** Check the exit code, not just the absence of output.

## Guardrails

- **Never** just delete the line and commit — the key is still in git history and is still valid.
- **Never** skip scanning on "internal" repos — internal repos get leaked too.
- **Never** ignore a real leak because "it's just a dev key" — dev keys often have broader access than expected.
- **Never** store the rotated replacement in the same repo without moving it to a secure location first.

## Pitfalls

- **Only scanning HEAD**: `git log` contains the full history. A secret committed 200 commits ago is still exposed. Always scan full history.
- **"Fixing" by deleting the line without rotating**: The key is still alive. The attacker already has it. Rotation is the ONLY real fix.
- **Treating a scan-pass as safety**: Scanners miss novel formats and low-entropy secrets. Defense in depth: never hardcode in the first place.
- **Forgetting to add the allowlist**: Without allowlisting known fixtures, the team learns to ignore all alerts.

## Verify / Checklist

- [ ] `gitleaks detect --no-git` (if applicable) returns no findings on the current tree
- [ ] `gitleaks detect` returns no findings on full git history (or only known allowlisted hits)
- [ ] Every found secret has been rotated (confirmed in provider console)
- [ ] Replacements are in env vars / secret store, not in the repo
- [ ] Pre-commit hook is installed (`gitleaks protect --staged`)
- [ ] CI pipeline includes a secret scan step
- [ ] `.gitleaks.toml` is present and reviewed for allowlist accuracy

Attached files

No attached files.