npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

shadowaudit

v2.0.0

Published

Static API security scanner — finds undocumented & unauthenticated routes across 8 frameworks (Express, FastAPI, Django, Flask, NestJS, Rails, Grape, Spring Boot). Maps to OWASP API Top 10.

Readme

☾☁ shadowaudit

Find shadow API routes before attackers do. Static analysis for 8 frameworks. Maps to OWASP API Top 10.

npm version npm downloads License: MIT Node.js


Quick Start (30 seconds)

npm install -g shadowaudit
shadowaudit --dir ./src

That's it. Every route in your codebase gets scanned, mapped to OWASP API Top 10, and scored 0-100.


Why shadowaudit?

The problem: Your API has routes that exist in code but aren't in your OpenAPI spec. These "shadow routes" are the #1 cause of API breaches — OWASP calls it API9 (Improper Inventory Management). shadowaudit finds them statically, before production.

The proof: Tested on real codebases — found 269 shadow routes in Ghost CMS, 2,449 routes in GitLab, with a 98.2% false-positive reduction on Mastodon's 766-route codebase.


What it looks like

┌──────────┬────────────────┬────────┬──────────────────────────────┬──────────────┐
│ SEVERITY │ OWASP          │ METHOD │ PATH                         │ AUTH         │
├──────────┼────────────────┼────────┼──────────────────────────────┼──────────────┤
│ CRITICAL │ API5 (BFLA)    │ POST   │ /admin/delete                │ [no auth]    │
│ CRITICAL │ API1 (BOLA)    │ GET    │ /api/internal/metrics        │ [no auth]    │
│ INFO     │ API9 (Shadow)  │ GET    │ /debug/*                     │ [env-only]   │
└──────────┴────────────────┴────────┴──────────────────────────────┴──────────────┘
┌─────────────────────────────────────────────┐
│  SCAN SUMMARY                               │
│  Risk Score           : 70/100              │
│  Risk Band            : MEDIUM RISK         │
└─────────────────────────────────────────────┘

── OWASP API Security Top 10 (2023) mappings ──
  API1: Broken Object Level Authorization (BOLA)
  API5: Broken Function Level Authorization (BFLA)
  API9: Improper Inventory Management (Shadow APIs)

5 auth statuses (v1.7.0 — cuts false positives dramatically):

| Status | Color | Meaning | |--------|-------|---------| | [auth] | 🟢 green | Route-level auth middleware detected | | [upstream-auth] | 🔵 blue | Auth applied globally via app.use(authenticate) | | [controller-auth] | 🔵 blue | Auth checked inside handler body (if (!req.user) return 401) | | [env-only] | 🟡 yellow | Route only mounted in dev/test env (if NODE_ENV === 'test') | | [no auth] | 🔴 red | No auth detected at any level — this is the one that matters |

Only [no auth] routes count as CRITICAL in the risk score. The other 4 statuses are INFO — no false alarms.


Features

Free tier (MIT licensed, no signup)

  • 8 frameworks: Express, FastAPI, Django, Flask, NestJS, Rails, Grape, Spring Boot
  • OWASP API Top 10 (2023) mapping — every finding maps to API1-API10
  • Risk score (0-100) — single number per scan, color-coded
  • 5 auth detection layers — route-level, upstream, controller, env-only, none
  • .shadowauditignore — glob patterns to exclude intentional routes
  • Table + JSON + SARIF + Markdown output — pipe into any CI tool
  • GitHub Actions annotations — inline ::error annotations on PR diffs
  • SARIF for GitHub Security tab — upload findings to GitHub's native security UI
  • Badge SVG — embed your risk score in your README

Pro tier ($19/mo founding rate · $40/mo standard)

  • 🔒 Cloud dashboard — scan history, trends, diff reports between deploys
  • 🔒 ABOM PDF reports — compliance-ready Application Bill of Materials
  • 🔒 Share links--share flag generates public read-only report URLs
  • 🔒 Unlimited scan history — track security debt over time

Install

npm install -g shadowaudit

Requires Node.js 18+.

Usage

# Basic scan — scans ./src, outputs colored table
shadowaudit --dir ./src

# With OpenAPI spec comparison — finds shadow routes (in code, not in spec)
shadowaudit --dir ./src --spec ./openapi.json

# SARIF output for GitHub Security tab
shadowaudit --dir ./src --format sarif > shadowaudit.sarif

# Check your cloud account tier & sync status (Free/Pro)
shadowaudit --status

# Save your dashboard token for --cloud
shadowaudit --cloud-login <your-token>

# Upload to cloud dashboard (Pro)
shadowaudit --dir ./src --cloud

# Generate ABOM PDF (Pro)
shadowaudit --dir ./src --abom

# Share report link (Pro)
shadowaudit --dir ./src --share

# Watch mode — re-scan on file change
shadowaudit --dir ./src --watch

GitHub Actions integration

Add this to .github/workflows/shadowaudit.yml:

name: shadowaudit
on: [push, pull_request]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm install -g shadowaudit
      - run: shadowaudit --dir ./src --format sarif > shadowaudit.sarif
      - uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: shadowaudit.sarif
      - run: shadowaudit --dir ./src --fail-on critical

CRITICAL findings block the PR. SARIF appears in GitHub's Security tab.


.shadowauditignore

Exclude intentional routes (health checks, metrics, debug endpoints) from findings:

# Health checks — intentionally public
/health
/healthz
/ready

# Internal metrics — exposed for monitoring
/api/internal/*

# Re-include a specific route (negation)
!/api/internal/health

Risk score recalculates based on remaining findings only.


Supported frameworks

| Framework | Auto-detect | Auth detection | OWASP mapping | |-----------|:-----------:|:--------------:|:-------------:| | Express | ✅ | ✅ | ✅ | | FastAPI | ✅ | ✅ | ✅ | | Django | ✅ | ✅ | ✅ | | Flask | ✅ | ✅ | ✅ | | NestJS | ✅ | ✅ | ✅ | | Rails | ✅ | ✅ | ✅ | | Grape | ✅ | ✅ | ✅ | | Spring Boot | ✅ | ✅ | ✅ |


Proven on real codebases

| Codebase | Routes found | Findings | False-positive rate | |----------|:------------:|:--------:|:-------------------:| | Ghost CMS | 269 shadow routes | 14 CRITICAL | 0% | | GitLab | 2,449 routes | 89 CRITICAL | 1.8% | | Mastodon | 766 routes | 23 CRITICAL | 1.8% (98.2% reduction) | | Spring PetClinic | 27 routes | 0 CRITICAL | 0% (0 false positives) |


Pricing

The CLI is free forever — all 8 frameworks, all output formats, unlimited scanning, no signup. Pro adds the hosted layer:

| | Open Source | Pro ($19/mo founding · $40/mo after) | |---|---|---| | Local scanning (all 8 frameworks) | ✓ unlimited | ✓ unlimited | | SARIF / JSON / markdown / table output | ✓ | ✓ | | ABOM generation + diffing (local) | ✓ | ✓ | | --fail-on CI policy gates | ✓ | ✓ | | Cloud dashboard sync (--cloud) | — | ✓ | | Scan history + trend tracking | — | ✓ | | Share links (--share) | — | ✓ | | Email alerts on CRITICAL findings | — | ✓ | | ABOM PDF export | — | ✓ |

The first 20 subscribers lock the founding rate — $19/mo or $179/yr for life. After that, Pro is $40/mo or $384/yr and every checkout link flips automatically — founding members keep their locked price from their original subscription.

Enterprise — SSO/SAML, team seats, custom scanners, compliance reporting, SLA. Priced individually — contact [email protected].

Payments — crypto (USDC, BTC, ETH, USDT) via Suby out of the box, or debit card: message us on WhatsApp and we'll set you up.

Check your tier anytime with shadowaudit --status. Manage billing or upgrade at the pricing page. 14-day full refund, no questions asked. Cancel anytime.

The promise: no feature that is free today will ever move behind a paywall. Pro adds collaboration and history — it never removes CLI capabilities.


v2.0.0 — Major Stabilization Release (Build, Allowlist & Framework Resolution)

  • Consolidated Build & Core Engine Stabilization: Resolved duplicate route matching utilities, fixed TypeScript syntax and compilation errors across all modules, and fully restored build stability.
  • Allowlist Wildcard & Type Hardening: Fixed crash (TypeError: pattern.endsWith is not a function) when handling non-string allowlist patterns and enhanced wildcard prefix (/*) and mid-path pattern matching.
  • Ancestor-Aware Auto-Detection: Restored reliable framework auto-detection for standard repository layouts where source code is located in subdirectories (./src).

v1.9.1 — Fixed the README quickstart (ancestor-aware framework detection)

  • shadowaudit --dir ./src now works on standard project layouts. v1.9.0's auto-detection only looked inside the scan directory, so any project with package.json at the repo root and sources in ./src — the exact layout in the 30-second quickstart above — failed with Could not auto-detect framework and exit 2. Detection now resolves in order: the scan dir itself (nearest marker wins), then the ancestor chain up to 5 levels up (covers repo roots and monorepo package roots), then the cwd. Monorepo-safe: a nested package declaring @nestjs/core wins over a root-level express dependency.
  • 5 new regression tests (520 total). Scanning behavior is unchanged — only framework resolution widened.

v1.9.0 — Free/Pro tier clarity, --status, and 30+ fixes from adversarial QA

Cloud & tiers:

  • Fixed cloud sync end-to-end — the CLI always sent its token via the Authorization header, but the dashboard API only read body.token, so --cloud failed with 400 Missing token field for every prior version. The API now accepts the header (all existing CLI versions work once the dashboard redeploys).
  • New --status — check your account tier (Free/Pro), masked email, scans synced, and last sync time without running a scan.
  • --cloud now works in every mode — previously it silently skipped the upload when no --spec was given (the guide's own --dir ./src --cloud example never synced) and in --format json|markdown scan-only mode. Uploads now run on all paths.
  • Friendlier tier errors — a 402 from --cloud prints a clear "cloud sync is a Pro feature, your local scan completed fine" message with the upgrade link instead of a raw API error.
  • Bare --cloud-login — running it without a token prints where to get one (sign in → copy token); empty/whitespace tokens are rejected.
  • Cleaner machine-readable output--cloud no longer prints [INFO] Uploading… after JSON/SARIF output (broke | jq); malformed dashboard responses fail loudly instead of fabricating a FREE account.
  • Default cloud URL corrected — the CLI now talks to shadowaudit-dashboard.vercel.app directly (the old default pointed at a .dev domain that was never ours and has since been registered by an unrelated project — do not use it).

Scanner fixes (found by 5-agent adversarial QA):

  • Grape support is now real — the Grape scanner shipped in v1.x but was never wired into auto-detection or --framework dispatch (unreachable dead code). Now: --framework grape works and Gemfile/lib/api/ detection returns it automatically.
  • router.use(requireAuth) detected — the very common Express idiom was invisible to upstream-auth detection; now marks subsequent routes [upstream-auth].
  • Optional-auth denylist extendedmaybeAuth, ifAuthenticated, optionalSession and friends no longer falsely mark routes as [auth] (these hid unauthenticated endpoints).
  • validateBearer-style middleware detectedbearer added to auth-name substrings.

CLI contract fixes:

  • Exit-code contract enforced — invalid --fail-on/--format/--concurrency values now exit 2 with a clear error (previously --fail-on medium printed "pipeline will FAIL" but exited 0).
  • --dir existence validated — a typo'd path previously "scanned" nothing and exited 0, silently passing CI.
  • --coverage --format json fixed — the JSON went to stderr, leaving stdout empty for | jq.
  • --coverage without --spec — now a clean exit-2 error (was a silent no-op).
  • --watch with relative ../ paths fixed — paths containing .. were treated as hidden and all file changes silently ignored.
  • --abom composes with all modes — previously --abom + --reverse/--coverage/--generate-spec never wrote the manifest; --abom without --spec produced phantom CRITICALs and a Spec file not found: undefined warning; unwritable --abom-output dumped a stack trace. All fixed.
  • ABOM risk scores are method-awareGET /x was marked documented (risk understated) whenever any method of /x was in the spec. Documented status now matches METHOD+PATH.

v1.8.0 — 3 false-positive fixes (array spread, Vue composables, CLI commands)

Found via adversarial QA scanning real-world repos (NodeBB, Directus, Strapi, KeystoneJS):

  • Array spread middleware detection[...middlewares] in route args now resolves the variable's array declaration and checks elements for auth indicators. Fixed 66 false positives on NodeBB's ActivityPub routes.
  • Vue.js composable exclusionuse-*.ts files are now excluded (Vue frontend composables, not Express server routes). Fixed 29 false positives on Directus.
  • CLI command + examples exclusioncli/commands/ and examples/ directories are now excluded. Fixed 20 false positives on Strapi, 3 on KeystoneJS.

| Repo | Before | After | Reduction | |------|:------:|:-----:|:---------:| | NodeBB | 66 [no auth] | 49 | -17 (26%) | | Directus | 30 routes | 1 | -29 | | Strapi | 28 routes | 1 | -27 | | KeystoneJS | 7 routes | 1 | -6 |

v1.7.0 — False-positive reduction: 3 new auth detection patterns

Cuts false positives by detecting 3 auth enforcement patterns the basic hasAuth check missed. Routes matching these patterns are downgraded from CRITICAL → INFO and no longer inflate the risk score.

  • [env-only] — routes mounted inside if (NODE_ENV === 'test') blocks. Detected via AST parent-chain walk (JS/TS) + indentation analysis (Python).
  • [controller-auth] — auth checked inside the handler body (if (!req.user) return res.status(401), Depends(get_current_user), etc.)
  • [upstream-auth] — auth middleware applied globally via app.use(authenticate) before the router is mounted in the same file.

Auth column now shows 5 statuses (was 2): [auth] green · [upstream-auth] blue · [controller-auth] blue · [env-only] yellow · [no auth] red

Only [no auth] routes count as CRITICAL in the risk score — the other 3 statuses are INFO, dramatically reducing false-positive risk scores.

20 new tests (515 total, all passing).

v1.6.0 — OWASP mapping, Risk Score, .shadowauditignore

  • OWASP API Security Top 10 (2023) mapping — every finding now shows its OWASP category inline (API1: BOLA, API5: BFLA, API9: Shadow APIs, etc.). Drop straight into security reports without manual lookup.
  • Risk Score (0-100) — every scan ends with a single risk score in the summary box. Formula: 100 − (critical×15) − (high×7) − (info×1), capped at 0. Bands: CRITICAL (0-30), HIGH (31-60), MEDIUM (61-80), LOW (81-100). Color-coded — instantly see if your API surface is improving or degrading.
  • .shadowauditignore support — like .gitignore but for routes. Place in your scan directory to exclude intentional routes (health checks, metrics, debug endpoints) from findings. Supports glob patterns + ! negation. Risk score is recalculated after filtering.
┌──────────┬────────────────┬────────┬──────────────────────────────┬──────┬──────┐
│ SEVERITY │ OWASP          │ METHOD │ PATH                         │ AUTH │
├──────────┼────────────────┼────────┼──────────────────────────────┼──────┼──────┤
│ CRITICAL │ API5 (BFLA)    │ POST   │ /admin/delete                │ NO   │
│ CRITICAL │ API1 (BOLA)    │ GET    │ /api/internal/metrics        │ NO   │
└──────────┴────────────────┴────────┴──────────────────────────────┴──────┴──────┘
┌─────────────────────────────────────────────┐
│  SCAN SUMMARY                               │
│  Risk Score           : 70/100              │
│  Risk Band            : MEDIUM RISK         │
└─────────────────────────────────────────────┘

── OWASP API Security Top 10 (2023) mappings in this scan ──
  API1: Broken Object Level Authorization (BOLA)
  API5: Broken Function Level Authorization (BFLA)

v1.5.0 — Post-scan CTA + --share + GitHub Actions annotations

  • Post-scan CTA block: after every scan (without --cloud), prints a branded block with the dashboard URL and badge markdown so users know where to view results
  • Token persistence: --cloud now saves the token to ~/.shadowaudit/token so future non-cloud scans show the correct dashboard URL
  • --share flag: creates a shareable read-only report link (expires in 7 days) by uploading results to /api/share
  • GitHub Actions annotations: when GITHUB_ACTIONS=true, emits ::error annotations for CRITICAL findings and ::warning for HIGH findings — visible in PR diffs
  • GitHub Actions step summary: when GITHUB_STEP_SUMMARY is set, appends a markdown table of critical/high findings to the run summary page
  • 69 new tests (495 total, all passing)

v1.3.0 — Framework validation & auth.optional fix

  • Framework validation--framework spring now works as alias for springboot. Invalid framework names exit with code 2.
  • auth.optional fix — Express scanner no longer treats auth.optional, authOptional, optionalAuth as auth (they mean auth is OPTIONAL, not required)
  • Spring Boot @ResponseBody fix — Methods with @ResponseBody annotation now extract correct method name (was showing unknown())
  • 11 new regression tests (426 total)

v1.2.0 — ABOM & Composite Risk Scoring

  • ABOM (API Bill of Materials) — generate a machine-readable inventory of every route in your app (the API equivalent of SBOM). Includes auth status, spec coverage, and per-route risk scores. See the ABOM section below.
  • Composite Risk Scoring — every route now gets a 0-100 risk score blending 7 factors: documentation gap, auth gap, exposure, method danger, path sensitivity, parameter complexity, and historical severity.
  • New flags: --abom, --abom-sign (ed25519), --abom-output <path>.
  • ABOM diff engine — compare two ABOMs to surface routes added, removed, or whose risk score changed between commits/releases.

v1.1.0 — Spring Boot scanner & adversarial QA

  • Spring Boot scanner — the 8th supported framework. Java parser for @RestController/@Controller with all @*Mapping shortcut annotations, class-level @RequestMapping base path prefixes, and Spring Security auth via @PreAuthorize/@PostAuthorize/@Secured/@RolesAllowed with class-level inheritance. Auto-detected via pom.xml or build.gradle.
  • --cloud flag — upload scan results to the shadowaudit cloud dashboard for cross-repo visibility.
  • Brutal adversarial QA — 27 new tests targeting 13 known weakness categories, run against the Spring PetClinic reference app.
  • 0% false-positive rate verified on Spring PetClinic.

v1.0.5 — Mastodon-scale false-positive reduction

  • 98.2% false-positive reduction on the Mastodon codebase (766 routes) via concern expansion + controller inheritance chain walking.
  • 9 new auth patterns added (Mastodon's require_moderator_or_admin_permissions, Discourse's requires_login, and others).
  • New --allowlist flag — JSON file of public route patterns that downgrade CRITICAL → INFO.
  • New scan-only mode — run without a spec to get a full route inventory.

Terminal Preview

shadowaudit ships with a colored, table-formatted terminal output. No screenshots needed — the ASCII previews below render on npm, GitHub, and in IDE markdown previews.

Basic scan (table format)

[INFO] shadowaudit v1.3.0
[INFO] Directory : ./src
[INFO] Spec file : ./openapi.json
[INFO] Framework : express
[INFO] Running Express.js route scanner...
[✓] Found 7 routes in ./src
[INFO] Detected spec: OpenAPI 3.x
[INFO] Spec contains 5 documented routes

╔══════════════════════════════════════════════╗
║           shadowaudit — Scan Report          ║
╚══════════════════════════════════════════════╝
┌──────────┬────────┬───────────────────────────────────┬──────────────────┬──────┬──────┐
│ SEVERITY │ METHOD │ PATH                              │ FILE             │ LINE │ AUTH │
├──────────┼────────┼───────────────────────────────────┼──────────────────┼──────┼──────┤
│ CRITICAL │ GET    │ /api/debug/reset                  │ routes.js        │ 21   │ NO   │
├──────────┼────────┼───────────────────────────────────┼──────────────────┼──────┼──────┤
│ CRITICAL │ POST   │ /api/test/seed                    │ routes.js        │ 22   │ NO   │
└──────────┴────────┴───────────────────────────────────┴──────────────────┴──────┴──────┘
┌─────────────────────────────────────┐
│  SCAN SUMMARY                       │
│  Total routes scanned : 7           │
│  Documented           : 5           │
│  Undocumented         : 2           │
│  🔴 CRITICAL          : 2           │
│  🟡 HIGH              : 0           │
│  🔵 INFO              : 0           │
└─────────────────────────────────────┘
⛔ Pipeline will FAIL — 2 critical shadow route(s) detected

ABOM summary (v1.2.0)

[INFO] Generating ABOM (abom-1.0)...
[✓] ABOM written to ./abom.json
[✓] ABOM signed with ed25519 (key id: 7f3a…c2e1)

╔════════════════════════════════════════════════════════════╗
║              shadowaudit — ABOM Summary                    ║
╚════════════════════════════════════════════════════════════╝
┌──────────────────────────────────┬─────────────────────────┐
│ Total routes                     │ 419                     │
│ Documented in spec               │ 287  (68.5%)            │
│ Undocumented                     │ 132  (31.5%)            │
│ Routes with auth                 │ 398  (95.0%)            │
│ Routes without auth              │ 21   (5.0%)             │
│ Avg risk score                   │ 34.2 / 100              │
│ Routes scoring ≥ 70 (high risk)  │ 17                      │
└──────────────────────────────────┴─────────────────────────┘

Top 5 highest-risk routes:
┌────────┬────────────────────────────────┬──────┬────────────┐
│ METHOD │ PATH                           │ AUTH │ RISK       │
├────────┼────────────────────────────────┼──────┼────────────┤
│ DELETE │ /api/admin/users/{id}          │ NO   │ 92 🔴      │
│ POST   │ /api/internal/import           │ NO   │ 87 🔴      │
│ GET    │ /api/debug/dump                │ NO   │ 84 🔴      │
│ PUT    │ /api/v2/settings               │ YES  │ 61 🟡      │
│ GET    │ /api/users/export.csv          │ YES  │ 54 🟡      │
└────────┴────────────────────────────────┴──────┴────────────┘

Installation

Global CLI (recommended)

npm install -g shadowaudit

npx (no install needed)

npx shadowaudit --dir ./src --spec ./openapi.json

Auto-generate an OpenAPI spec (new!)

Don't have a spec yet? Generate one from your code:

shadowaudit --dir ./src --framework express --generate-spec > openapi.json

Then review the generated spec, fill in response schemas, and use it for delta comparison.

GitHub Action

Add to .github/workflows/security.yml:

- uses: darkmaster0345/[email protected]
  with:
    dir: './src'
    spec: './openapi.json'
    fail-on: 'critical'

Real-World Testing

shadowaudit has been tested against real production codebases to validate accuracy and guide the roadmap:

TryGhost/Ghost — production publishing platform (Express.js)

  • 269 routes detected across admin API, content API, members API, and webhooks
  • 235 routes correctly authenticated (v0.3.0 AST-based detection catches custom authAdminApi middleware)
  • 0 config.get() false positives (v0.3.0 object-name filtering eliminates these)
  • 34 routes legitimately public (session, authentication, setup, webhooks — verified manually)

tiangolo/fastapi — FastAPI framework docs (FastAPI)

  • 419 routes detected across documentation source examples
  • All route patterns correctly parsed: @app.get(), @router.post(), path parameters, Depends() auth
  • Auto-spec generation tested: --generate-spec produces valid OpenAPI 3.0.3 from scanned routes

expressjs/express — Express framework examples (Express.js)

  • 58 routes detected across 15+ example applications
  • Mount prefix reconciliation working: USE /api/v1 and USE /api/v2 correctly identified
  • Auth detection working: POST /login correctly flagged as [auth]

pallets/flask — Flask framework source (Flask)

  • 3 internal routes detected in Flask's own source code
  • Flask <param> syntax correctly converted to {param}
  • Blueprint routes (@bp.route()) detected

hagopj13/node-express-boilerplate (Express.js)

  • 18 routes detected across auth, user, and docs modules
  • v0.2.1 auth( pattern fix correctly detected auth on 6 user routes that v0.2.0 missed
  • Mount prefix reconciliation working for app.use('/prefix', require('./router')) pattern

mastodon/mastodon — federated social network (Rails + Grape)

  • 766 routes detected (743 Rails + 23 from concern expansion)
  • 0 unknown#unknown controller actions (v0.9.0 concern expansion eliminated all 5 false positives from v0.8.2)
  • Controller inheritance chain walking correctly detected auth in 385 routes (v0.8.0 had 96 — 57% false-positive reduction)
  • Community OpenAPI spec comparison: 601 undocumented shadow routes found (the community spec only covers the public REST API, not web/admin/settings routes)

gitlabhq/gitlabhq — DevSecOps platform (Rails + Grape)

  • 2,449 routes detected (1,423 Rails web routes + 1,017 Grape API routes + 9 other)
  • 1,017 /api/v4/ routes from Grape lib/api/*.rb files (v0.9.0 Grape scanner)
  • 813 routes with auth detected via Grape before do authenticate! end blocks
  • Mount chain resolution working: mount ::API::Groupslib/api/groups.rb with /api/v4 prefix
  • GitLab's OpenAPI spec has 1,144 paths — 2,136 undocumented shadow routes found

These real-world tests directly shaped the roadmap — each limitation found is now a tracked improvement with priority and effort ratings.


The Problem

Developers spin up quick test endpoints and forget to remove them. These shadow APIs bypass documentation, skip auth middleware, and get deployed to production silently — invisible to network scanners, invisible to your security team.

shadowaudit solves this by statically analyzing your codebase, comparing every route definition against your OpenAPI/Swagger spec, and failing your CI pipeline before the PR merges if it finds undocumented or unauthenticated routes.


What shadowaudit does

  • Scans your codebase for all actual route definitions (Express.js, FastAPI, and Django supported)
  • Compares them against your OpenAPI 3.x / Swagger 2.0 spec
  • Flags any route missing from the documentation
  • Detects whether auth middleware is applied to each route
  • Fails your CI/CD pipeline before the PR merges — with exit codes that respect configurable severity thresholds

Severity levels

| Severity | Condition | CI behavior (--fail-on critical) | |----------|-----------|-------------------------------------| | CRITICAL | Undocumented route + no auth middleware | Pipeline fails | | HIGH | Undocumented route + auth middleware present | Pipeline passes (review recommended) | | INFO | Informational finding | Pipeline passes |


Supported Frameworks

  • Express.js ✅ (AST-based route extraction via Babel, mount prefix reconciliation, 3-level deep router chain resolution, auth detection)
  • FastAPI ✅ (decorator-based route extraction, Depends() auth detection, include_router prefix reconciliation)
  • Django ✅ (path()/re_path()/url() extraction, DRF router support, class-based views (ModelViewSet, APIView, generics), include() prefix reconciliation, cross-file auth via views.py)
  • Flask ✅ (@app.route() / @bp.route() decorator extraction, methods= multi-method (list + tuple syntax), Blueprint url_prefix support, @login_required auth detection)
  • NestJS ✅ (@Controller() + @Get() / @Post() decorator extraction, @UseGuards() auth detection, @Public() override, @Version() API versioning, controller prefix + method path combination)
  • Rails ✅ (v0.8.0+ — config/routes.rb block-aware parser: namespace, scope, resources/resource macros, member/collection blocks, devise_for, draw(:subfile), concern expansion, with_options, controller: modifier, cross-file auth via before_action with controller inheritance chain walking + module-nested parent class resolution, 25+ auth patterns including Mastodon's require_moderator_or_admin_permissions and Discourse's requires_login)
  • Grape ✅ (v0.9.0+ — lib/api/*.rb Grape API scanner: resource, namespace, route_param, before auth blocks, mount cross-file resolution, prefix/version support. Auto-invoked when lib/api/ exists. Tested on GitLab: 1,017 /api/v4/ routes detected)
  • Spring Boot ✅ (v1.1.0+ — Java parser for @RestController/@Controller classes: @GetMapping/@PostMapping/@PutMapping/@DeleteMapping/@PatchMapping shortcut annotations, @RequestMapping with method= parameter, class-level @RequestMapping base path prefix, Spring Security auth detection via @PreAuthorize/@PostAuthorize/@Secured/@RolesAllowed with class-level inheritance. Auto-detected via pom.xml or build.gradle.)

CLI Options

Usage: shadowaudit [options]

Static API security scanner for undocumented routes

Options:
  -V, --version       output the version number
  --dir <path>        Directory to scan (default: current directory)
  --spec <path>       Path to OpenAPI/Swagger spec file
  --format <type>     Output format: table, json, sarif, markdown (default: "table")
  --fail-on <level>   Fail CI pipeline on: critical, high, info (default: "critical")
  --framework <name>  Force framework: express, fastapi, django, flask, nestjs, rails, springboot (alias: spring) (Grape auto-detected) (default: "auto")
  --generate-spec     Generate OpenAPI spec from scanned routes (no comparison)
  --diff              Show only new findings since last scan (requires --spec)
  --concurrency <n>   Parallel file scan concurrency (default: 8, max: 64)
  --watch             Watch for file changes and re-scan automatically (debounced 300ms, Ctrl+C to exit)
  --reverse           Find dead spec entries (routes in spec NOT in code)
  --coverage          Score OpenAPI spec completeness (descriptions, params, responses, security)
  --ignore-paths <paths>  Comma-separated paths to ignore (exact, /prefix/*, or * for all)
  --allowlist <file>  JSON file with public route patterns (downgrades CRITICAL → INFO)
  --abom              Generate an API Bill of Materials (abom-1.0) alongside scan results
  --abom-sign         Sign the ABOM with ed25519 (requires ABOM_SIGNING_KEY env var)
  --abom-output <path> Write ABOM JSON to file (default: ./abom.json)
  --abom-diff <a> <b> Diff two ABOM files (added / removed / risk-changed routes)
  --cloud             Upload scan results to the shadowaudit cloud dashboard (Pro)
  --cloud-login [token] Save your dashboard API token (bare flag shows where to get one)
  --status            Show your cloud account tier (Free/Pro) and sync status
  -h, --help          display help for command

Exit codes

| Code | Meaning | |------|---------| | 0 | Clean scan — no findings, or findings below --fail-on threshold | | 1 | Findings found at or above --fail-on threshold | | 2 | Tool error (spec file missing/invalid, framework not detected, etc.) |


API Bill of Materials (ABOM)

New in v1.2.0. The ABOM is the API equivalent of an SBOM (Software Bill of Materials) — a machine-readable inventory of every route your application exposes, including auth status, spec coverage, and a per-route composite risk score. Ship it alongside your build artifacts so downstream teams (security, SRE, compliance) can audit your attack surface without re-running the scanner.

Generating an ABOM

shadowaudit --dir ./src --spec ./openapi.json --abom

Writes ./abom.json (override the path with --abom-output <path>). The normal scan still runs — ABOM is additive and does not change exit-code behavior.

Signing the ABOM (ed25519)

export ABOM_SIGNING_KEY=$(cat ./ed25519-private.key)
shadowaudit --dir ./src --spec ./openapi.json --abom --abom-sign

A signed ABOM includes a signature block that consumers verify with the corresponding public key before trusting the inventory:

{
  "signature": {
    "algorithm": "ed25519",
    "publicKey": "7f3a...c2e1",
    "value": "3044...8aaf"
  }
}

Composite Risk Scoring (0-100)

Every route in the ABOM gets a riskScore from 0 (safe) to 100 (critical). The score is a weighted blend of seven factors:

| Factor | Weight | Description | |-------------------------|--------|-------------| | Documentation gap | 25 | Route is missing from the OpenAPI spec | | Auth gap | 25 | No auth middleware detected on the route | | Exposure | 15 | Route is reachable from a public-facing base path | | Method danger | 15 | Mutating methods (DELETE, PUT, POST) score higher than GET | | Path sensitivity | 10 | Path contains keywords like admin, debug, internal, config, users | | Parameter complexity | 5 | Path contains {id}-style params (injection / IDOR surface) | | Historical severity | 5 | Boost if similar paths have triggered findings in past scans |

| Score | Severity | Meaning | |------------|---------------------|--------------------------------------| | 70-100 | 🔴 CRITICAL | Fix immediately — likely exploitable | | 40-69 | 🟡 HIGH | Review before merge | | 0-39 | 🟢 LOW | Informational |

ABOM diff engine

Compare two ABOMs to surface what changed between commits, releases, or branches:

shadowaudit --abom-diff ./abom-main.json ./abom-feature.json

Output highlights routes added, removed, or whose risk score changed by ≥ 5 points — perfect for PR review. Pairs naturally with --diff mode so the scan itself only reports new findings while the ABOM diff shows full route-level churn.

Example ABOM output

The terminal summary printed after a --abom run is shown in the Terminal Preview above. The full machine-readable artifact is the abom.json file described by the schema below.

ABOM JSON schema (abom-1.0)

{
  "schema": "abom-1.0",
  "generatedAt": "2026-02-10T14:23:01.000Z",
  "tool": "shadowaudit",
  "toolVersion": "1.3.0",
  "project": {
    "dir": "./src",
    "spec": "./openapi.json",
    "framework": "express"
  },
  "summary": {
    "totalRoutes": 419,
    "documented": 287,
    "undocumented": 132,
    "withAuth": 398,
    "withoutAuth": 21,
    "averageRiskScore": 34.2,
    "highRiskCount": 17
  },
  "routes": [
    {
      "method": "DELETE",
      "path": "/api/admin/users/{id}",
      "file": "routes/admin.js",
      "line": 142,
      "hasAuth": false,
      "documented": false,
      "riskScore": 92,
      "riskFactors": [
        "documentation-gap",
        "auth-gap",
        "path-sensitivity",
        "method-danger"
      ],
      "severity": "CRITICAL"
    }
  ],
  "signature": {
    "algorithm": "ed25519",
    "publicKey": "7f3a...c2e1",
    "value": "3044...8aaf"
  }
}

Quick Start

# Scan your codebase against your OpenAPI spec
shadowaudit --dir ./src --spec ./openapi.json

# Force a specific framework
shadowaudit --dir ./src --spec ./openapi.json --framework express

# Only show NEW findings since last scan (perfect for PRs)
shadowaudit --dir ./src --spec ./openapi.json --diff

# Don't have a spec? Generate one from your code
shadowaudit --dir ./src --framework express --generate-spec > openapi.json

# Output as JSON (pipe to jq for CI integrations)
shadowaudit --dir ./src --spec ./openapi.json --format json | jq '.findings | length'

# Output as SARIF 2.1.0 (for GitHub Code Scanning)
shadowaudit --dir ./src --spec ./openapi.json --format sarif > results.sarif

--diff mode (v0.6.0+)

Show only new findings since the last scan — perfect for PR workflows where you don't want to see the same 50 pre-existing findings on every PR.

# First run — full scan, cache saved
shadowaudit --dir ./src --spec ./openapi.json --diff

# Second run — only NEW findings shown
shadowaudit --dir ./src --spec ./openapi.json --diff
  • Cache stored at .shadowaudit-cache.json (auto-added to .gitignore)
  • Resolved findings shown as green ✓ section
  • Exit code based on NEW findings only (pre-existing findings don't fail CI)
  • For GitHub Actions: use actions/cache to persist .shadowaudit-cache.json between runs

--watch mode (v0.7.0+)

Re-scan automatically whenever you save a file — perfect for dev-time feedback while you're writing new routes.

shadowaudit --dir ./src --spec ./openapi.json --watch
  • Debounced 300ms — bursty saves (editor "save all", formatter runs) trigger one re-scan, not five
  • Ctrl+C exits cleanly with exit code 0 (no orphaned processes)
  • Works with --diff to show only NEW findings per save
  • Only watches .js, .ts, .jsx, .tsx, .py files; ignores node_modules, dist, __pycache__, .git
  • Cannot be combined with --generate-spec or --format json/sarif (table only — JSON isn't streamable)

--concurrency <n> (v0.7.0+)

Control how many files are read in parallel during a scan. Defaults to 8, clamped to [1, 64].

# Use higher concurrency on a beefy CI box
shadowaudit --dir ./src --spec ./openapi.json --concurrency 16

# Force sequential (same as v0.6.1 behavior)
shadowaudit --dir ./src --spec ./openapi.json --concurrency 1
  • Output is deterministic regardless of concurrency (verified by adversarial QA — concurrency=1 and concurrency=64 produce byte-identical route arrays)
  • Invalid values (0, negative, non-numeric) degrade gracefully to the default
  • 3-5× speedup on large codebases (Ghost CMS: 4s → ~1s)

--generate-spec (v0.4.0+)

Don't have an OpenAPI spec? Generate one from your code:

shadowaudit --dir ./src --framework express --generate-spec > openapi.json

Configuration

shadowaudit loads config from two sources (CLI flags take priority):

  1. CLI flags (highest priority)
  2. .shadowaudit.yml or .shadowauditrc.yml in your project root

📖 Full configuration documentation → — all fields, examples, and troubleshooting.

Example .shadowaudit.yml:

spec: ./openapi.json
dir: ./src
format: table
failOn: critical
authPatterns:
  - myCustomAuth
  - requireLogin
ignore:
  - node_modules
  - dist
  - build

Default auth patterns (always detected)

Even without custom config, shadowaudit detects these auth middleware patterns:

.authenticate(    .authorize(       requireAuth        isAuthenticated
verifyToken       checkAuth         ensureLoggedIn     passport.authenticate
jwt.verify        bearerAuth        apiKeyAuth         basicAuth

Output Formats

Table (default)

Human-readable colored table with severity, method, path, file, line, and auth status. Includes a summary box and pipeline recommendation.

JSON

Structured JSON for CI dashboards and log aggregators:

{
  "scanMeta": {
    "tool": "shadowaudit",
    "version": "1.3.0",
    "timestamp": "2026-01-15T12:00:00.000Z",
    "stats": { "total": 7, "documented": 5, "undocumented": 2, "critical": 2, "high": 0, "info": 0 }
  },
  "findings": [
    {
      "severity": "CRITICAL",
      "method": "GET",
      "path": "/api/debug/reset",
      "file": "routes.js",
      "line": 21,
      "hasAuth": false,
      "reason": "Undocumented route with no authentication middleware detected — publicly accessible shadow API"
    }
  ],
  "documentedRoutes": [...]
}

SARIF 2.1.0

Industry-standard format for GitHub Code Scanning, Azure DevOps, and other security dashboards. Maps findings to two rules:

| Rule ID | Severity | Level | |---------|----------|-------| | SHADOW001 | CRITICAL | error | | SHADOW002 | HIGH | warning | | SHADOW002 | INFO | note |


Demo

Below is the actual terminal output from an end-to-end scan. The test project has 7 Express routes — 5 documented in the OpenAPI spec, 2 undocumented shadow routes with no auth middleware:

[INFO] No config file found, using defaults
[INFO] shadowaudit v1.3.0
[INFO] Directory : /tmp/auth-test
[INFO] Spec file : /tmp/auth-test/openapi.json
[INFO] Format    : table
[INFO] Fail on   : critical
[INFO] Framework : express
[INFO] Running Express.js route scanner...
[✓] Found 7 routes in /tmp/auth-test
[INFO]   GET /public/health → routes.js:6 [auth]
[INFO]   GET /public/products → routes.js:7 [auth]
[INFO]   GET /api/users → routes.js:9 [auth]
[INFO]   POST /api/users → routes.js:13 [auth]
[INFO]   GET /api/admin/dashboard → routes.js:17 [auth]
[INFO]   GET /api/debug/reset → routes.js:21 [no auth]
[INFO]   POST /api/test/seed → routes.js:22 [no auth]
[INFO] Detected spec: OpenAPI 3.x
[INFO] Spec contains 5 documented routes
[INFO] ──────────────────────────────────────────────────
[INFO] Total routes scanned : 7
[INFO] Documented           : 5
[INFO] Undocumented         : 2
[INFO] ──────────────────────────────────────────────────
╔══════════════════════════════════════════════╗
║           shadowaudit — Scan Report          ║
╚══════════════════════════════════════════════╝
┌──────────┬────────┬───────────────────────────────────┬───────────────────────────────────┬──────┬──────┐
│ SEVERITY │ METHOD │ PATH                              │ FILE                              │ LINE │ AUTH │
├──────────┼────────┼───────────────────────────────────┼───────────────────────────────────┼──────┼──────┤
│ CRITICAL │ GET    │ /api/debug/reset                  │ routes.js                         │ 21   │ NO   │
├──────────┼────────┼───────────────────────────────────┼───────────────────────────────────┼──────┼──────┤
│ CRITICAL │ POST   │ /api/test/seed                    │ routes.js                         │ 22   │ NO   │
└──────────┴────────┴───────────────────────────────────┴───────────────────────────────────┴──────┴──────┘
┌─────────────────────────────────────────────┐
│  SCAN SUMMARY                               │
│  Total routes scanned : 7                   │
│  Documented           : 5                   │
│  Undocumented         : 2                   │
│  ─────────────────────────────────────────  │
│  🔴 CRITICAL          : 2                   │
│  🟡 HIGH              : 0                   │
│  🔵 INFO              : 0                   │
└─────────────────────────────────────────────┘
⛔ Pipeline will FAIL — 2 critical shadow route(s) detected
Exit code: 1

In the terminal, severity cells are color-coded:

  • CRITICAL → red bold
  • HIGH → yellow bold
  • INFO → blue
  • METHOD → cyan
  • AUTH YES → green / NO → red

How It Works

┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  Express Scanner │     │  Spec Parser     │     │  Delta Comparator│     │  Formatter       │
│  (Babel AST)     │     │  (OpenAPI/Swagger)│     │  (normalize +   )│     │  (table/json/    )│
│                  │     │                  │     │  ( match routes )│     │  (sarif)         )│
│  src/**/*.js     │────▶│  openapi.json    │────▶│  Route[] vs      │────▶│  Findings[]      │
│  src/**/*.ts     │     │  swagger.yaml    │     │  DocumentedRoute[]│     │  + stats         │
│                  │     │                  │     │                  │     │                  │
│  + auth detector │     │  + basePath      │     │  + severity      │     │  + exit code     │
│  (window scan)   │     │  + serverPrefix  │     │  scoring         │     │  logic           │
└──────────────────┘     └──────────────────┘     └──────────────────┘     └──────────────────┘
  1. Express scanner uses @babel/parser + @babel/traverse to walk every .js/.ts file's AST and extract route definitions (app.get(), router.post(), router.route().get().post() chaining, etc.)
  2. Auth detector scans a ±15-line window around each route for auth middleware patterns (inline or in surrounding scope), with sibling-route lines stripped to avoid false positives
  3. Spec parser reads OpenAPI 3.x / Swagger 2.0 files (JSON or YAML), extracts documented routes, and normalizes path syntax ({id}:id)
  4. Delta comparator cross-references scanned routes against documented routes, reconciling Swagger basePath and OpenAPI servers[0].url prefixes, then scores each undocumented route as CRITICAL (no auth) or HIGH (has auth)
  5. Formatter renders the report as a colored table, JSON, or SARIF 2.1.0

CI/CD Integration

GitHub Actions

name: Security Scan
on: [pull_request]

jobs:
  shadowaudit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npx shadowaudit --dir ./src --spec ./openapi.json --format sarif > shadowaudit.sarif
        continue-on-error: true
      - uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: shadowaudit.sarif
      - name: Fail on critical
        run: npx shadowaudit --dir ./src --spec ./openapi.json --fail-on critical

GitLab CI

# .gitlab-ci.yml
shadowaudit:
  image: node:20
  script:
    - npm ci
    - npx shadowaudit --dir ./src --spec ./openapi.json --format json > shadowaudit.json
    - npx shadowaudit --dir ./src --spec ./openapi.json --fail-on critical
  artifacts:
    paths:
      - shadowaudit.json
    when: always

Pre-commit hook

#!/bin/bash
shadowaudit --dir ./src --spec ./openapi.json --fail-on critical

Project Structure

shadowaudit/
├── src/
│   ├── index.ts              # CLI entry point
│   ├── action.ts             # GitHub Action entry point
│   ├── config.ts             # cosmiconfig loader (CLI flags + .shadowaudit.yml)
│   ├── comparator.ts         # Delta comparator (route diffing + severity scoring)
│   ├── diff.ts               # --diff mode (local cache + new/resolved detection)
│   ├── types.ts              # Shared TypeScript interfaces
│   ├── scanners/
│   │   ├── express.ts        # Express.js route extractor (Babel AST + mount prefixes)
│   │   ├── fastapi.ts        # FastAPI route extractor (decorators + include_router)
│   │   ├── django.ts         # Django route extractor (path() + CBV + cross-file auth)
│   │   ├── flask.ts          # Flask route extractor (@app.route + methods=)
│   │   ├── nestjs.ts         # NestJS route extractor (@Controller + @Get decorators)
│   │   ├── rails.ts          # Rails routes.rb parser (namespace, resources, concerns)
│   │   ├── grape.ts          # Grape API scanner (lib/api/*.rb)
│   │   ├── springboot.ts     # Spring Boot scanner (@RestController + @GetMapping)
│   │   └── auth.ts           # Auth middleware detector (AST + string-based)
│   ├── parsers/
│   │   └── spec.ts           # OpenAPI 3.x / Swagger 2.0 parser
│   ├── formatters/
│   │   ├── table.ts          # Colored terminal table
│   │   ├── json.ts           # JSON output
│   │   ├── sarif.ts          # SARIF 2.1.0 output
│   │   └── index.ts          # Formatter dispatcher
│   ├── generators/
│   │   └── spec.ts           # Auto-spec generation (--generate-spec)
│   ├── github/
│   │   └── comment.ts        # PR comment bot
│   └── utils/
│       └── logger.ts         # Colored console output
├── tests/                    # 426 tests across 27 files
│   ├── config.test.ts
│   ├── comparator.test.ts
│   ├── diff.test.ts
│   ├── hardening.test.ts
│   ├── placeholder.test.ts
│   ├── v1-features.test.ts
│   ├── watch.test.ts
│   ├── scanners/
│   │   ├── express.test.ts
│   │   ├── fastapi.test.ts
│   │   ├── django.test.ts
│   │   ├── django-cbv.test.ts
│   │   ├── flask.test.ts
│   │   ├── nestjs.test.ts
│   │   ├── rails.test.ts
│   │   ├── rails-concerns.test.ts
│   │   ├── rails-resource.test.ts
│   │   ├── grape.test.ts
│   │   ├── springboot.test.ts
│   │   ├── auth.test.ts
│   │   └── parallel.test.ts
│   ├── parsers/
│   │   └── spec.test.ts
│   ├── generators/
│   │   └── spec.test.ts
│   ├── formatters/
│   │   ├── table.test.ts
│   │   └── sarif.test.ts
│   └── github/
│       └── comment.test.ts
├── docs-site/                # Docusaurus v3 documentation site
├── scripts/                  # Migration + deployment helpers
│   ├── prepublish-check.ts
│   ├── gitlab-migrate.sh
│   └── docs-deploy.sh
├── action.yml                # GitHub Marketplace Action definition
├── ROADMAP.md                # v1.2.0 → v1.3.0+ roadmap
├── CONTRIBUTING.md           # How to add framework scanners
├── package.json
├── tsconfig.json
├── LICENSE
└── README.md

Development

# Install dependencies
npm install

# Build
npm run build

# Run tests (426 tests across 27 test files)
npm test

# Run in dev mode
npm run dev -- --dir ./src --spec ./openapi.json

# Lint
npm run lint

Tech Stack

  • TypeScript — strict mode, ES2020 target, CommonJS modules
  • Babel (@babel/parser + @babel/traverse) — AST-based route extraction with error recovery
  • Commander.js — CLI argument parsing
  • chalk — terminal colors
  • cli-table3 — terminal table rendering
  • js-yaml — Swagger/OpenAPI YAML parsing
  • cosmiconfig — config file discovery
  • glob — recursive file scanning
  • Vitest — test runner

Privacy & Network Access

shadowaudit runs entirely locally — it reads your source files and OpenAPI spec on disk. No code is uploaded, no telemetry is sent, no phone-home.

The only network call is when using the GitHub Action's PR comment bot (post-comment: 'true'), which posts the findings summary to the GitHub API (api.github.com) using github.token. This is the standard GitHub Actions pattern and uses your repo's own token — no external servers are contacted.

Socket.dev audit: ✅ Vulnerability 100/100 · ✅ Quality 100/100 · ✅ License 100/100


License

MIT © Ubaid ur Rehman 2026