v0.1.0 · MIT · Node 18+

Find risky JS/TS code
before it ships.

PathBug is a local-first CLI scanner for security, dependency, config, bug-prone, and quality issues. Best-effort static analysis — your source never leaves your machine.

npm install -g pathbug
pathbug scan . # scan current directory
Rules
23 across 5 categories
Engine
AST + intra-file taint
Network
Zero outbound for analysis
pathbug · ~/projects/sample-app
 $ pathbug scan . --no-progress pathbug v0.1.0 · scanned 142 files in 480ms SECURITY (4) [HIGH] security/eval-usage src/handlers/run.ts:18 Use of eval() [HIGH] security/hardcoded-secret src/config/db.ts:3 Possible hardcoded Stripe live key BUG (2) [MED] bug/floating-promise src/jobs/sync.ts:42 [MED] bug/empty-catch src/utils/cache.ts:88 ──────────────────────────────────────── Summary: 6 findings (2 high, 2 medium) · exit 1 
How it works

From install to CI in five commands.

  1. 01

    Install once

    Global npm install. ~200 KB unpacked.

    npm install -g pathbug
  2. 02

    Run pathbug

    TUI in a TTY, banner everywhere else.

    pathbug
  3. 03

    Scan a path

    Recursive walk honoring .gitignore.

    pathbug scan .
  4. 04

    Read the report

    Grouped by severity and category in your terminal.

    pathbug scan . --severity high
  5. 05

    Export for CI

    Structured JSON for pipelines, jq, artifacts.

    pathbug scan . --json --output report.json
  6. 06

    Source stays local

    No upload. No telemetry. No registry except your own npm audit.

    # nothing leaves your machine
Local-first

Built so your source code can't leave by accident.

Static scanners that silently ship code off-machine became an incident category of their own. PathBug is explicit about what it touches and what it doesn't.

Network behaviour
Source upload
Never. PathBug reads from disk and writes findings to your terminal or stdout.
Telemetry
None. No analytics endpoint, no usage pings, no error reporting beacons.
External analysis
No third-party AI, SaaS analyzers, or remote rule services.
npm audit
Runs your local npm. Disable with --disable dependency/audit.
What lives on disk
Project files
Read-only. Scanned project is never modified — verified by a sha256 diff test.
~/.pathbug/config
Your preferred default scan path, severity, and globs. Local only.
~/.pathbug/recent
Last 20 scans, metadata only — path + timestamp + counts. No source, snippets, or findings.
~/.pathbug/reports
Optional JSON exports. Never inside the scanned project.

The full network policy is documented in SECURITY.md. Recent-scan metadata-only behaviour is asserted by a test in the repo.

23 rules · 5 categories

Detection coverage.

Honest scope: deterministic + heuristic checks. Names match the ruleId you'll see in JSON output and on every finding.

01

Security

Mostly AST + intra-file taint
security/hardcoded-secret high

API keys, tokens, passwords, .env credential lines, connection strings.

const STRIPE = "sk_live_…"
security/eval-usage high

Calls to eval(...) — executes arbitrary input as code.

eval(req.body.expr)
security/new-function high

new Function(...) — same hazard as eval, harder to spot.

new Function('x', body)
security/shell-injection high

exec/spawn/execSync of tainted input from req.{query,body,params,headers}.

exec(`tar -xf ${req.query.f}`)
security/sql-injection high

Template or concat SQL with tainted input. Suggests parameterised queries.

`SELECT * WHERE id=${id}`
security/path-traversal high

fs.* sinks reading tainted paths — flags at the actual sink, not path.join.

fs.readFile(req.query.p)
security/cors-misconfig medium

Wildcard CORS with credentials, origin: "*" patterns.

cors({ origin: '*', credentials: true })
security/weak-crypto medium

md5, sha1, Math.random() for tokens, deprecated crypto APIs.

crypto.createHash('md5')
02

Bugs

Promise + control-flow gotchas
bug/empty-catch medium

catch (e) { } with no rethrow, log, or recovery.

try { … } catch (e) { }
bug/floating-promise medium

Promise producers at statement position with no await/then/catch.

fetch(url) // dropped
bug/unsafe-any-cast medium

as any / <any> casts that silently disable the type checker.

(payload as any).id
bug/loose-equality low

== / != — flagged so coercion bugs are at least visible.

if (id == '1')
03

Dependency

package.json + npm audit
dependency/unsafe-version-range high

*, latest, or >0.0.0 ranges in package.json.

"react": "*"
dependency/suspicious-scripts high

preinstall/postinstall scripts shelling out to curl/wget.

"postinstall": "curl … | sh"
dependency/audit medium

Local npm audit counts per severity. No CVE detail surfaced.

npm audit --json
dependency/duplicate-deps low

Same package in dependencies and devDependencies.

dep + devDep collide
04

Config

.env, CI, Dockerfile, tsconfig
config/exposed-env high

.env appears to be committed to the repo.

.env in tree
config/ci-leaks-secret high

Secrets echoed in GitHub Actions / GitLab CI workflows.

echo $SECRET
config/dockerfile-risks low

FROM with no tag, USER root, ADD http, curl | sh, COPY .env*.

FROM node # no tag
config/tsconfig-strict low

tsconfig.json without strict: true.

"strict": false
05

Quality

Soft signals, off by --severity
quality/debug-statements low

console.log / debugger in non-test code.

console.log(user)
quality/todo-fixme low

TODO / FIXME / XXX markers anywhere in the tree.

// FIXME: race condition
quality/large-file low

Files past a sane line-count threshold.

1200-line component
Two modes, one binary

Interactive at your desk. JSON in your pipeline.

Run pathbug with no arguments in a real terminal and you get an Ink-based TUI. Pipe it, redirect it, or set PATHBUG_NO_INTERACTIVE=1 and it falls back to plain text or JSON automatically.

Interactive

For your dev loop

pathbug · TTY — home screen
 $ pathbug ┌──────────────────────────────┐  pathbug v0.1.0   Local static analysis  ├──────────────────────────────┤   Scan a project   Recent scans   Open last report   Settings   Help   Exit  └──────────────────────────────┘ ↑↓ move · ↵ select · q quit 
  • Pick a path with arrow keys
  • Toggle severity, include/exclude globs, fixtures
  • Filterable report viewer, jump straight to a finding
  • Recent scans (metadata only)
CI / scripted

For your pipeline

github actions · .github/workflows/security-scan.yml
 name: Security scan
on: [push, pull_request]
jobs: pathbug: runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npx -y pathbug scan . --severity high
      - run: npx -y pathbug scan . --json --output pathbug.json
if: always()
      - uses: actions/upload-artifact@v4
with: name: pathbug-report
path: pathbug.json
  • Plain text in non-TTY by default
  • --json for stdout, --output file.json for artefacts
  • Exit 1 on ≥ high so it gates a job step
  • --rules / --disable to scope what fails the build
Exit codes stable across TUI / text / JSON
  • 0scan completed; no high/critical findings
  • 1at least one finding at high or critical
  • 2runtime error (path missing, etc.)
Honest limits

What PathBug is and isn't.

Static scanners that overpromise erode trust the first time they miss something. This is what PathBug does not do — written down.

Not a full SAST replacement
PathBug is heuristic with some AST analysis. Use it alongside CodeQL, Semgrep, Snyk, or a security review — never instead of them.
Not a runtime / business-logic detector
Auth bypasses that depend on the shape of your data model, IDOR, or broken assumptions in flows will not be caught. Those need humans or fuzzing.
Not a cross-file taint engine
Taint tracking is intra-file: req.* aliases inside one file are followed. Tainted values that travel through another module are not.
Not language-universal
Structural rules target JS/TS. Quality rules like quality/todo-fixme opportunistically apply to other text formats; nothing else does.
Not a secret scanner of record
security/hardcoded-secret catches the obvious patterns. For revocation / partner notification, use a dedicated scanner with provider feeds.
Not an autofixer
PathBug reports. It never modifies the project being scanned — verified by a temp-fixture sha256 diff in the test suite.

If PathBug is the only thing between your code and production, you don't have enough things between your code and production.

Quick start

Install, run, gate. In that order.

01

Install

npm install -g pathbug # canonical
bun install -g pathbug # expected — to verify
pnpm add -g pathbug # alt
yarn global add pathbug # alt

Node 18+. The published tarball is ~49 KB, ~200 KB unpacked. Bun support is the documented intent — the package exposes a Node-shebanged ESM bundle as its bin, the standard shape Bun expects. If bun install -g fails on your version, please file an issue.

02

Run

pathbug # interactive home
pathbug scan . # one-shot
pathbug scan . --severity high # only high+
pathbug scan . --include 'src/**/*.ts' # narrow scope

Honors .gitignore. Skips node_modules, binaries, and files over 1 MB by default. Per-file rule suppressions via // pathbug-disable rule/id comments.

03

Gate

pathbug scan . --json # stdout
pathbug scan . --output report.json # auto-JSON if .json
pathbug scan . --rules security/eval-usage # allowlist
pathbug scan . --disable quality/todo-fixme # denylist

Wire into any CI as a normal run step. Exit 1 on ≥ high. JSON envelope is stable: scanner, version, stats, summary, findings[].