
Security News
/Research
Fake Corepack Site Distributes Infostealer and Proxyware to Developers
A fake corepack.org site is impersonating the Node.js tool and delivers an infostealer and proxyware to developers who download it.
shadowaudit
Advanced tools
Static API security scanner — detects undocumented and unauthenticated Express.js routes before they reach production
Static API security scanner — finds undocumented and unauthenticated routes before they reach production
🌐 Documentation & Demo → · 🛒 GitHub Marketplace →
npm install -g shadowaudit
npx shadowaudit --dir ./src --spec ./openapi.json
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.
Add to .github/workflows/security.yml:
- uses: darkmaster0345/shadow-Audit@v0.9.0
with:
dir: './src'
spec: './openapi.json'
fail-on: 'critical'
shadowaudit has been tested against real production codebases to validate accuracy and guide the roadmap:
authAdminApi middleware)config.get() false positives (v0.3.0 object-name filtering eliminates these)@app.get(), @router.post(), path parameters, Depends() auth--generate-spec produces valid OpenAPI 3.0.3 from scanned routesUSE /api/v1 and USE /api/v2 correctly identifiedPOST /login correctly flagged as [auth]<param> syntax correctly converted to {param}@bp.route()) detectedauth( pattern fix correctly detected auth on 6 user routes that v0.2.0 missedapp.use('/prefix', require('./router')) patternThese real-world tests directly shaped the roadmap — each limitation found is now a tracked improvement with priority and effort ratings.
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.
| 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 |
Depends() auth detection, include_router prefix reconciliation)path()/re_path()/url() extraction, DRF router support, class-based views (ModelViewSet, APIView, generics), include() prefix reconciliation, cross-file auth via views.py)@app.route() / @bp.route() decorator extraction, methods= multi-method (list + tuple syntax), @login_required auth detection)@Controller() + @Get() / @Post() decorator extraction, @UseGuards() auth detection, @Public() override, controller prefix + method path combination)config/routes.rb block-aware parser: namespace, scope, resources/resource macros, member/collection blocks, devise_for, draw(:subfile), cross-file auth via before_action in controllers)npm install -g shadowaudit
Or use it locally in your project:
npm install --save-dev shadowaudit
# 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
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 (default: "table")
--fail-on <level> Fail CI pipeline on: critical, high, info (default: "critical")
--framework <name> Force framework: express, fastapi, django, flask, nestjs, rails (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) [v0.7.0+]
--watch Watch for file changes and re-scan automatically [v0.7.0+]
-h, --help display help for command
--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
.shadowaudit-cache.json (auto-added to .gitignore)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
--diff to show only NEW findings per save.js, .ts, .jsx, .tsx, .py files; ignores node_modules, dist, __pycache__, .git--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
concurrency=1 and concurrency=64 produce byte-identical route arrays)--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
| Condition | Exit code |
|---|---|
| No findings | 0 |
Findings below --fail-on threshold | 0 |
Findings at or above --fail-on threshold | 1 |
--fail-on value | Fails when |
|---|---|
critical (default) | Any CRITICAL finding |
high | Any CRITICAL or HIGH finding |
info | Any finding at all |
shadowaudit loads config from two sources (CLI flags take priority):
.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
Even without custom config, shadowaudit detects these auth middleware patterns:
.authenticate( .authorize( requireAuth isAuthenticated
verifyToken checkAuth ensureLoggedIn passport.authenticate
jwt.verify bearerAuth apiKeyAuth basicAuth
Human-readable colored table with severity, method, path, file, line, and auth status. Includes a summary box and pipeline recommendation.
Structured JSON for CI dashboards and log aggregators:
{
"scanMeta": {
"tool": "shadowaudit",
"version": "0.9.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": [...]
}
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 |
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
╔════════════════════════════════╗
║ shadowaudit v0.9.0 ║
║ API Shadow Route Scanner ║
╚════════════════════════════════╝
[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:
YES → green / NO → red┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 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 │
└──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘
@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.){id} → :id)basePath and OpenAPI servers[0].url prefixes, then scores each undocumented route as CRITICAL (no auth) or HIGH (has auth)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
#!/bin/bash
shadowaudit --dir ./src --spec ./openapi.json --fail-on critical
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=)
│ │ └── 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/ # 139 tests across 16 files
│ ├── config.test.ts
│ ├── comparator.test.ts
│ ├── diff.test.ts
│ ├── scanners/
│ │ ├── express.test.ts
│ │ ├── fastapi.test.ts
│ │ ├── django.test.ts
│ │ ├── django-cbv.test.ts
│ │ ├── flask.test.ts
│ │ └── auth.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
├── .github/workflows/
│ ├── shadowaudit.yml # CI: build + test + self-scan
│ └── deploy-docs.yml # Docs auto-deploy to GitHub Pages
├── action.yml # GitHub Marketplace Action definition
├── ROADMAP.md # v0.8.0 → v1.0.0 roadmap
├── CONTRIBUTING.md # How to add framework scanners
├── package.json
├── tsconfig.json
├── LICENSE
└── README.md
# Install dependencies
npm install
# Build
npm run build
# Run tests (139 tests across 16 test files)
npm test
# Run in dev mode
npm run dev -- --dir ./src --spec ./openapi.json
# Lint
npm run lint
@babel/parser + @babel/traverse) — AST-based route extraction with error recoveryshadowaudit 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
MIT © Ubaid ur Rehman 2026
FAQs
Static API security scanner — detects undocumented and unauthenticated Express.js routes before they reach production
The npm package shadowaudit receives a total of 567 weekly downloads. As such, shadowaudit popularity was classified as not popular.
We found that shadowaudit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
/Research
A fake corepack.org site is impersonating the Node.js tool and delivers an infostealer and proxyware to developers who download it.

Research
/Security News
A large-scale campaign abused GitHub Actions in compromised repositories to exploit CVE-2026-41940 in cPanel and WHM and steal server credentials.

Security News
Five frontier LLMs generated the same nonexistent package names, leaving 53 available for potential slopsquatting across PyPI and npm.