Topic: mcp server secret scanning security

MCP server secret scanning security — detecting hardcoded credentials, pre-commit hooks, and git history remediation

MCP servers are typically developed quickly and published to public GitHub repositories early in their lifecycle. The same speed that makes the MCP ecosystem vibrant creates a credential leak pattern that SkillAudit's scan data confirms: approximately 40% of community MCP servers contain at least one hardcoded credential in their git history, even if that credential was removed from the current HEAD. A secret committed to git — even in a commit that was later deleted — persists in reflog, fork clones, and automated harvest bots that scrape public repositories. Secret scanning must happen before the commit, not after it is public.

The secret leak lifecycle in MCP server development

The typical credential leak follows a predictable pattern:

  1. Development shortcut. The author pastes a real API key into config.js or .env.example to get the server running locally, intending to replace it before pushing.
  2. Accidental commit. git add . captures the file. The commit goes to the public repo.
  3. Delayed discovery. The author notices (or is notified by GitHub's push protection or a security researcher) and removes the key in a follow-up commit.
  4. False sense of resolution. The key is gone from HEAD, but git history is permanent. The key is in every clone and fork made between step 2 and step 4.
  5. Parallel harvesting. Automated bots that watch GitHub's event stream for credential patterns (Gitleaks, TruffleHog, specialized credential harvesters) processed the repository within minutes of step 2. The key was likely already tested and potentially used.

The window between commit and revocation — during which the credential is live and public — is typically measured in hours or days. The right mitigation is not faster revocation; it is preventing the commit from happening in the first place.

The most common credential types in MCP server repos

SkillAudit's credential exposure scan identifies these credential types in community MCP servers most frequently:

Fix 1 — pre-commit secret detection with detect-secrets

detect-secrets (Yelp's open-source tool) scans staged content for high-confidence secret patterns before the commit is finalized. Installing it as a pre-commit hook blocks the commit if any patterns match:

# Install detect-secrets
pip install detect-secrets

# Generate a baseline of known false positives in the repo
detect-secrets scan --baseline .secrets.baseline

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.4.0
    hooks:
      - id: detect-secrets
        args: ['--baseline', '.secrets.baseline']

# Install the hooks
pre-commit install

# Now every git commit runs detect-secrets on staged files.
# If a new secret is found that isn't in the baseline, the commit is blocked:
#
# Detect secrets...................................................Failed
# - hook id: detect-secrets
# - exit code: 1
# ERROR: Potential secrets found.
# Secret Type: Secret Keyword
# Location:    src/config.js:12 (stripe_secret_key)

Fix 2 — git-secrets for AWS and common credential patterns

git-secrets (AWS Labs) focuses on AWS credential patterns and integrates directly as a git hook rather than through the pre-commit framework:

# Install git-secrets
brew install git-secrets  # macOS
# or build from source on Linux

# Register AWS patterns (built-in)
git secrets --register-aws

# Add custom patterns for other credential types
git secrets --add 'sk_live_[a-zA-Z0-9]{24}'      # Stripe live keys
git secrets --add 'sk-ant-[a-zA-Z0-9\-]{95}'      # Anthropic keys
git secrets --add 'ghp_[a-zA-Z0-9]{36}'            # GitHub PATs
git secrets --add 'postgresql://[^:]+:[^@]+'        # Postgres connection strings

# Install as a hook in the current repo
git secrets --install

# Or install globally for all new repos
git secrets --install ~/.git-templates/git-secrets
git config --global init.templateDir ~/.git-templates/git-secrets

Fix 3 — CI pipeline secret scanning with TruffleHog

Pre-commit hooks rely on developers having them installed. CI-level scanning catches secrets that slip through on developer machines where hooks were not installed, or in commits made through the GitHub web UI:

# GitHub Actions workflow: scan every pull request for secrets
name: Secret Scan

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  trufflehog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # Full history — TruffleHog scans all commits

      - name: TruffleHog Secret Scan
        uses: trufflesecurity/trufflehog@main
        with:
          path: ./
          base: ${{ github.event.repository.default_branch }}
          head: HEAD
          extra_args: --only-verified   # Only alert on verified (active) credentials

--only-verified makes TruffleHog test the detected credential against the issuing API before alerting — this dramatically reduces false positives and ensures alerts represent real, currently-active leaked credentials.

Fix 4 — remediation when a secret is already in git history

If a credential is already in the repository's git history, removing it from HEAD is not sufficient. The credential must be revoked immediately (rotation, deletion, or scope restriction at the issuing service) and the git history must be rewritten:

# Step 1: Revoke the credential immediately — do this FIRST before any git operations
# (git history rewrite is slower than credential compromise)

# Step 2: Rewrite git history using git filter-repo (preferred over BFG)
pip install git-filter-repo

# Remove a specific file from all commits
git filter-repo --path config.js --invert-paths

# Or replace all occurrences of the secret string
git filter-repo --replace-text <(echo 'ACTUAL_SECRET_VALUE==>REDACTED')

# Step 3: Force-push to remote (requires branch protection bypass — coordinate with team)
git push origin main --force

# Step 4: Notify all existing forks — GitHub's "delete fork network" for critical leaks
# Step 5: Rotate any credentials that were in those forks

SkillAudit detection

SkillAudit scans both the current HEAD and the full commit history (for public repositories) for credential patterns. The Credential exposure axis includes:

The Credential exposure score is one of the highest-weight axes in the SkillAudit overall grade because it is the most immediately actionable risk: a detected secret can be revoked and rotated immediately, unlike architectural flaws that require refactoring. See the credential leak anatomy post for the full taxonomy of credential exposure patterns that SkillAudit detects, including runtime leaks (credentials echoed in logs or tool responses) in addition to the static code patterns covered here.