Skip to content

Secret Scanner Comparison Benchmark #33

Secret Scanner Comparison Benchmark

Secret Scanner Comparison Benchmark #33

---
name: Secret Scanner Comparison Benchmark
on:
workflow_dispatch:
schedule:
# Run weekly on Sundays at 02:00 UTC
- cron: '0 2 * * 0'
permissions:
contents: read
jobs:
trufflehog:
runs-on: ubuntu-latest
outputs:
count: ${{ steps.count.outputs.findings }}
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Run TruffleHog OSS
run: |
# Use TruffleHog directly to capture JSON output properly
docker run --rm -v "$(pwd):/pwd" \
trufflesecurity/trufflehog:latest filesystem /pwd \
--json --only-verified > trufflehog_output.json || true
continue-on-error: true
id: trufflehog
- name: Count TruffleHog findings
id: count
run: |
# Count findings from TruffleHog output (it outputs JSON lines)
count=0
if [ -f trufflehog_output.json ]; then
count=$(cat trufflehog_output.json | \
grep -c "\"verified\":" || echo "0")
fi
echo "findings=$count" >> $GITHUB_OUTPUT
echo "TruffleHog found $count verified secrets"
git-secrets:
runs-on: ubuntu-latest
outputs:
count: ${{ steps.count.outputs.findings }}
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Install git-secrets
run: |
git clone https://github.com/awslabs/git-secrets.git
cd git-secrets
sudo make install
- name: Initialize git-secrets
run: |
git secrets --register-aws
git secrets --install
- name: Run git-secrets scan
id: scan
run: |
set +e
git secrets --scan > git_secrets_output.txt 2>&1
exit_code=$?
echo "exit_code=$exit_code" >> $GITHUB_OUTPUT
cat git_secrets_output.txt
continue-on-error: true
- name: Count git-secrets findings
id: count
run: |
count=0
if [ -f git_secrets_output.txt ]; then
# Count lines that indicate findings (exclude headers/empty lines)
count=$(grep -c ".*:.*:.*" git_secrets_output.txt || echo "0")
fi
echo "findings=$count" >> $GITHUB_OUTPUT
echo "git-secrets found $count secrets"
detect-secrets:
runs-on: ubuntu-latest
outputs:
count: ${{ steps.count.outputs.findings }}
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Install detect-secrets
run: |
pip install detect-secrets
- name: Run detect-secrets scan
run: |
detect-secrets scan --all-files > detect_secrets_output.json
continue-on-error: true
- name: Count detect-secrets findings
id: count
run: |
count=0
if [ -f detect_secrets_output.json ]; then
# Count the number of potential secrets found
count=$(jq '.results | to_entries | map(.value | length) | \
add // 0' detect_secrets_output.json)
fi
echo "findings=$count" >> $GITHUB_OUTPUT
echo "detect-secrets found $count potential secrets"
gitleaks:
runs-on: ubuntu-latest
outputs:
count: ${{ steps.count.outputs.findings }}
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Install gitleaks
run: |
wget -O gitleaks.tar.gz \
https://github.com/gitleaks/gitleaks/releases/download/v8.18.4/gitleaks_8.18.4_linux_x64.tar.gz
tar -xf gitleaks.tar.gz
sudo mv gitleaks /usr/local/bin/
gitleaks version
- name: Run gitleaks scan
run: |
gitleaks detect --source . --report-format json \
--report-path gitleaks_output.json --no-git || \
echo "Gitleaks scan completed"
continue-on-error: true
- name: Count gitleaks findings
id: count
run: |
count=0
if [ -f gitleaks_output.json ]; then
# Count findings in JSON output
count=$(jq 'length' gitleaks_output.json 2>/dev/null || echo "0")
fi
echo "findings=$count" >> $GITHUB_OUTPUT
echo "gitleaks found $count secrets"
gittyleaks:
runs-on: ubuntu-latest
outputs:
count: ${{ steps.count.outputs.findings }}
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Install gittyleaks
run: |
pip install gittyleaks
- name: Run gittyleaks scan
run: |
gittyleaks --find-anything > gittyleaks_output.txt 2>&1
continue-on-error: true
- name: Count gittyleaks findings
id: count
run: |
count=0
if [ -f gittyleaks_output.txt ]; then
# Count lines that contain findings (exclude header/footer lines)
count=$(grep ":" gittyleaks_output.txt | \
grep -v "Bot Detective" | grep -v "^---" | \
wc -l || echo "0")
fi
echo "findings=$count" >> $GITHUB_OUTPUT
echo "gittyleaks found $count secrets"
whispers:
runs-on: ubuntu-latest
outputs:
count: ${{ steps.count.outputs.findings }}
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Install whispers (with timeout handling)
run: |
# Try to install whispers with a timeout and fallback
timeout 300 pip install whispers || echo "Failed to install whispers"
continue-on-error: true
- name: Run whispers scan
run: |
if command -v whispers >/dev/null 2>&1; then
whispers . --output whispers_output.json --format json || \
echo "Whispers scan failed"
else
echo "Whispers not available, skipping scan"
echo "[]" > whispers_output.json
fi
continue-on-error: true
- name: Count whispers findings
id: count
run: |
count=0
if [ -f whispers_output.json ]; then
# Count findings in JSON output
count=$(jq 'length' whispers_output.json 2>/dev/null || echo "0")
fi
echo "findings=$count" >> $GITHUB_OUTPUT
echo "whispers found $count secrets"
trufflehog3:
runs-on: ubuntu-latest
outputs:
count: ${{ steps.count.outputs.findings }}
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Install trufflehog3
run: |
pip install trufflehog3
- name: Run trufflehog3 scan
run: |
trufflehog3 . --format json > trufflehog3_output.json 2>&1 || \
echo "TruffleHog3 scan completed with warnings"
continue-on-error: true
- name: Count trufflehog3 findings
id: count
run: |
count=0
if [ -f trufflehog3_output.json ]; then
# Count findings - each line that starts with '{' is a finding
count=$(grep -c '^{' trufflehog3_output.json || echo "0")
fi
echo "findings=$count" >> $GITHUB_OUTPUT
echo "trufflehog3 found $count secrets"
summary:
needs: [trufflehog, git-secrets, gitleaks, detect-secrets, gittyleaks,
whispers, trufflehog3]
runs-on: ubuntu-latest
steps:
- name: Create Summary Report
run: |
echo "# Secret Scanner Comparison Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Scanner | Secrets Found |" >> $GITHUB_STEP_SUMMARY
echo "|---------|---------------|" >> $GITHUB_STEP_SUMMARY
echo "| TruffleHog | ${{ needs.trufflehog.outputs.count }} |" \
>> $GITHUB_STEP_SUMMARY
echo "| git-secrets | ${{ needs.git-secrets.outputs.count }} |" \
>> $GITHUB_STEP_SUMMARY
echo "| gitleaks | ${{ needs.gitleaks.outputs.count }} |" \
>> $GITHUB_STEP_SUMMARY
echo "| detect-secrets |" \
"${{ needs.detect-secrets.outputs.count }} |" \
>> $GITHUB_STEP_SUMMARY
echo "| gittyleaks | ${{ needs.gittyleaks.outputs.count }} |" \
>> $GITHUB_STEP_SUMMARY
echo "| whispers | ${{ needs.whispers.outputs.count }} |" \
>> $GITHUB_STEP_SUMMARY
echo "| trufflehog3 | ${{ needs.trufflehog3.outputs.count }} |" \
>> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Total unique scanning tools tested:** 7" \
>> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "_This benchmark helps understand the relative effectiveness" \
"of different secret scanning tools on the OWASP WrongSecrets" \
"repository._" >> $GITHUB_STEP_SUMMARY
# Also output to console
echo "=== Secret Scanner Comparison Results ==="
echo "TruffleHog: ${{ needs.trufflehog.outputs.count }} secrets"
echo "git-secrets: ${{ needs.git-secrets.outputs.count }} secrets"
echo "gitleaks: ${{ needs.gitleaks.outputs.count }} secrets"
echo "detect-secrets: ${{ needs.detect-secrets.outputs.count }} \
secrets"
echo "gittyleaks: ${{ needs.gittyleaks.outputs.count }} secrets"
echo "whispers: ${{ needs.whispers.outputs.count }} secrets"
echo "trufflehog3: ${{ needs.trufflehog3.outputs.count }} secrets"