Skip to main content

Sample Report

A real run of scan4secrets against a planted-secret fixture (SAST) and against the docs site you are reading (DAST). Both runs are reproduced here so you can see exactly what the tool produces before installing it.

Every secret value below is a clearly fake placeholder (AWS documentation example values, or strings stamped with FAKE). Nothing in this report authenticates.

Tool version

$ scan4secrets --version
scan4secrets 2.1.0

Run 1, SAST against a planted fixture

Target

A small fixture tree representing a typical web application:

sample-app/
├── .env.production # cloud, payment, AI, messaging tokens
├── src/config.js # Meta access token, OAuth, webhook
├── config/service-account.json # GCP service-account JSON, PEM block
├── .github/workflows/deploy.yml # CI log echo with PAT and PyPI token
└── build/bundle.min.js.map # JS source-map exposing original auth.ts

Command

scan4secrets --path sample-app \
--report sarif json jsonl csv html excel pdf \
--output reports/sast-sample-app

Summary

SeverityCount
critical6
high7
medium3
low3
info0
Total19

Per-rule breakdown:

RuleHits
github-pat-classic3
stripe-secret-live2
slack-bot-token2
slack-webhook2
generic-high-entropy-unquoted2
anthropic-key1
meta-access-token1
private-key-block1
postgres-connection-uri1
redis-connection-uri1
mongodb-connection-uri1
jwt-token1
generic-high-entropy-quoted1

Every finding

SeverityRuleFileLineRedacted value
criticalgithub-pat-classic.env.production12ghp_********************************AAAA
criticalgithub-pat-classic.github/workflows/deploy.yml10ghp_********************************9988
criticalgithub-pat-classicsrc/config.js8ghp_********************************0011
criticalprivate-key-blockconfig/service-account.json5----*******************----
criticalstripe-secret-live.env.production6sk_l********************************FAKE
criticalstripe-secret-livesrc/config.js15sk_l******************************0000
highanthropic-key.env.production10sk-a**************************************AAAA
highmeta-access-tokensrc/config.js3EAAB**************************************0099
highmongodb-connection-uri.env.production28mong***************************.net
highpostgres-connection-uri.env.production26post***************************prod
highredis-connection-uri.env.production27redi***********6379
highslack-bot-token.env.production15xoxb******************************FAKE
highslack-bot-tokensrc/config.js11xoxb******************************FAKE
mediumjwt-tokensrc/config.js26eyJh***********************************************EFAK
mediumslack-webhook.env.production16http*************************************************XXXX
mediumslack-webhooksrc/config.js12http*************************************************AAAA
lowgeneric-high-entropy-quotedsrc/config.js4abcd****************7890
lowgeneric-high-entropy-unquoted.env.production3wJal********************************EKEY
lowgeneric-high-entropy-unquoted.github/workflows/deploy.yml9pypi***************************************FAKE

Regenerate the full report locally

The report artifacts are not committed to the repo. GitHub push protection flags the embedded line_excerpt lines (planted AWS docs example values, etc.) as real secrets. Reproduce locally to see the exact same output in all seven formats.

git clone https://github.com/m14r41/scan4secrets
cd scan4secrets
pip install -e .

# Build a fixture (or use yours)
mkdir -p sample-app && cat > sample-app/.env.production <<'EOF'
AWS_ACCESS_KEY_ID=AKIA<...AWS-DOCS-EXAMPLE-VALUE...>
STRIPE_SECRET_KEY=sk_live_FAKE_FAKE_FAKE_FAKE_FAKE
GITHUB_PAT=ghp_FAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKE00
EOF

# Run the same command this page describes
scan4secrets --path sample-app \
--report sarif json jsonl csv html excel pdf \
--output reports/sast-sample-app

Each of the seven outputs will land in reports/:

FormatWhen to use
SARIFGitHub Code Scanning, GitLab Security Dashboard, Sonar, Defect Dojo
JSONTooling integration, post-processing
JSONLSIEM and SOAR streaming (Splunk, Datadog, Sentinel)
CSVSpreadsheet triage
HTMLSortable, filterable client view
ExcelPivot tables and exec summaries
PDFCompliance evidence packets

Run 2, DAST against this docs site

Target

http://127.0.0.1:3000 (the same Docusaurus site you are reading, run locally).

Command

scan4secrets --url http://127.0.0.1:3000 \
--threads 16 --max-urls 200 --max-depth 2 --timeout 8 \
--no-wordlist \
--report sarif json jsonl csv html excel pdf \
--output reports/dast-localhost

--no-wordlist disables the bundled 1279-path wordlist seeding for this demo. In a real bug-bounty engagement you would leave wordlist seeding on. --max-urls 200 --max-depth 2 keeps the run bounded for a demo.

Summary

SeverityCount
critical2
high0
medium0
low0
info0
Total2

Why this is interesting

Both findings fire on /docs/targets/github because that page documents the shape of GitHub deploy keys, and the description includes the literal anchor line:

-----BEGIN OPENSSH PRIVATE KEY-----

The detection rule private-key-block is doing exactly what it is supposed to do, this is a true positive on the page content. In a real engagement these would be triaged out as documentation false positives by passing --exclude '**/docs/targets/**' or by adding an allowlist.paths entry to the rule.

This is the most useful kind of demo finding because it shows two important things in one run:

  1. The scanner does fire on a real PEM anchor in any served HTML, not just in source.
  2. Documentation pages that explain attack surface need a per-rule allowlist or a --exclude path filter, or they will land in every report.

Regenerate the DAST report locally

# After installing scan4secrets and running the docs site at localhost:3000
scan4secrets --url http://127.0.0.1:3000 \
--threads 16 --max-urls 200 --max-depth 2 --timeout 8 \
--no-wordlist \
--report sarif json jsonl csv html excel pdf \
--output reports/dast-localhost

How to read the output

SARIF

SARIF is the standard for code-scanning dashboards. Each finding becomes a result with a ruleId, a physicalLocation (file plus start line), a level (error for critical and high, warning for medium, note for low and info), and a properties block carrying the entropy score and the verified state.

{
"ruleId": "github-pat-classic",
"level": "error",
"message": { "text": "GitHub Personal Access Token (Classic)" },
"locations": [{
"physicalLocation": {
"artifactLocation": { "uri": "sample-app/.env.production" },
"region": { "startLine": 12 }
}
}],
"properties": { "entropy": 4.81, "verified": null, "redacted": "ghp_****AAAA" }
}

Upload it to GitHub Code Scanning:

- uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: reports/sast-sample-app.sarif }

JSONL

One finding per line, ready to pipe into a SIEM or transform with jq. The fastest format to grep against.

# everything critical and high, file + line + rule
jq -r 'select(.severity=="critical" or .severity=="high")
| [.severity, .rule_id, .file, .line] | @tsv' sast-sample-app.jsonl
critical github-pat-classic sample-app/.env.production 12
critical github-pat-classic sample-app/.github/workflows/deploy.yml 10
critical github-pat-classic sample-app/src/config.js 8
critical private-key-block sample-app/config/service-account.json 5
critical stripe-secret-live sample-app/.env.production 6
critical stripe-secret-live sample-app/src/config.js 15
high anthropic-key sample-app/.env.production 10
high meta-access-token sample-app/src/config.js 3
...

HTML

Open in any browser. Severity is colored, columns are sortable, the search bar filters live. Best for sharing with a client who does not want to install anything.

CSV and Excel

Same data shape, optimized for spreadsheet triage. Excel adds a summary sheet with pivot tables (severity by rule, severity by file).

PDF

Compliance evidence. Stable layout, ASCII-safe encoding. Hands cleanly to an auditor.

JSON

Full structured output with every finding, every rule, the run metadata, and the tool version. The most precise feed for downstream tooling that wants the complete picture.

Exit-code semantics

Both runs above did not pass --fail-on, so the exit code was 0 regardless of finding count. Add a gate to make CI fail on real incidents.

scan4secrets --path sample-app --report sarif \
--fail-on high \
--output reports/sast-sample-app

--fail-on high exits 1 if any finding is high or critical. The SARIF file is still produced so the dashboard upload still runs.

Reproduce this run

  1. Install scan4secrets (Getting Started).
  2. Pull a copy of the fixture into a temp directory or build your own.
  3. Run the two commands from this page.
  4. Diff the output against the reports linked above.

The fixture used here is intentionally small, 6 files. Real engagements produce reports with hundreds to thousands of findings. The shape is identical.