Skip to main content

pkg-doctor

Scan your local projects for known-vulnerable or hijacked dependencies, and get guided, human-approved help rotating any API keys that might be exposed as a result.

pip install pkg-doctor
pkg-doctor --path ./my-project

The problem

Every so often a popular package gets compromised - a maintainer's account is hijacked, or malicious code slips into a new release. When it happens, the advisory that follows always says the same thing: "rotate all your API keys." Nobody actually knows which of their dozen local projects use the affected version, so people either panic-rotate everything or ignore the warning and hope for the best.

pkg-doctor replaces the guessing with one command: it tells you exactly which local projects are affected, and walks you through fixing exactly those - nothing more.


What it does

pkg-doctor --path ~/projects/foo
pkg-doctor --path ~/projects/foo --path ~/projects/bar --include-self
  1. Scans the directories you name for dependency manifests (requirements.txt, package-lock.json)
    • nothing is scanned unless you pass --path.
  2. Checks every pinned package against OSV.dev - a free, public vulnerability database that also ingests the OpenSSF malicious-packages feed, which is exactly the "a package got hijacked" case, not just an ordinary CVE. Results are flagged and clearly distinguished: MALICIOUS PACKAGE vs. VULNERABLE.
  3. If a project is flagged, it checks that project's .env/config files for key-shaped strings (OpenAI, Anthropic, Google, AWS, GitHub patterns, plus a lower-confidence generic fallback) - values are only ever shown masked (sk-ab12...wx9y), never logged or transmitted anywhere.
  4. For each possible exposed key, it asks you first. Nothing is ever rotated automatically. Say yes, and it opens the provider's key-management dashboard in your browser and walks you through revoking the old key and generating a new one - then waits for your confirmation before moving on.

No API key, no LLM, no account required. It never sends anything more than a package name, ecosystem, and version to OSV.dev - never file contents, paths, or secret values.


Install

pip install pkg-doctor

Works on Windows, macOS, and Linux - Python 3.10+, only two dependencies (click, requests).


Usage

# Scan one project
pkg-doctor --path ./my-project

# Scan several at once
pkg-doctor --path ~/dev/billing-service --path ~/dev/auth-service

# Also audit pkg-doctor's own installed dependencies
pkg-doctor --path ./my-project --include-self

# Skip the config-file scan entirely (vulnerability check only)
pkg-doctor --path ./my-project --skip-secrets

Example output:

~/dev/billing-service
  MALICIOUS PACKAGE: some-lib==2.1.0 (MAL-2026-4821)
    https://osv.dev/vulnerability/MAL-2026-4821

  Possible exposed secret (high confidence)
    Provider: OpenAI
    File:     ~/dev/billing-service/.env
    Value:    sk-ab12...wx9y
  Rotate this key now? [y/N]:

What it deliberately does not do

  • Never rotates anything without your explicit y - no automation, no "trust me" mode.
  • Never touches secrets managers (HashiCorp Vault, AWS Secrets Manager, etc.) - it only reads local flat files (.env, .env.local, .env.production, .env.development, config.json, secrets.json, credentials.json, .npmrc). If your secrets already live in a real vault, this tool has nothing to say about them - but the dependency-vulnerability check still applies regardless of where secrets live.
  • Never scans anything you didn't name - no default-scan-your-whole-drive behavior.
  • Never calls an LLM - this is plain text/JSON/TOML/YAML parsing plus one REST API call to OSV.dev. Nothing here reads or transmits your files through a language model.

Supported manifests

Ecosystem File Notes
Python (pip) requirements.txt Exact-pinned name==version lines only - unpinned lines are reported separately, not silently skipped
Python (Poetry) poetry.lock
Node (npm) package-lock.json Lockfile v1/v2/v3
Node (Yarn) yarn.lock Classic (v1) and Berry (v2+)
Node (pnpm) pnpm-lock.yaml lockfileVersion 5/6/9 key formats
Go go.sum
Java/Kotlin (Gradle) gradle.lockfile Modern single-file dependency locking (opt-in via dependencyLocking)
Java (Maven) pom.xml Only literally-pinned <version> tags - versions from a parent POM/BOM, a ${property}, or a range are reported as unverifiable, not guessed at (Maven has no resolved-lockfile equivalent)

Other manifests found (Pipfile.lock, Gemfile.lock, build.gradle, build.gradle.kts) are reported as "found but not yet supported" rather than silently ignored - build.gradle/.kts are executable scripts, not data, so they aren't parsed; enable Gradle dependency locking for accurate scanning instead.


License

MIT - see LICENSE

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pkg_doctor-0.1.0.tar.gz (14.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pkg_doctor-0.1.0-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file pkg_doctor-0.1.0.tar.gz.

File metadata

  • Download URL: pkg_doctor-0.1.0.tar.gz
  • Upload date:
  • Size: 14.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.11

File hashes

Hashes for pkg_doctor-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b741e7510df99ff90bdd85b6447bedd9aa4d9d14ee4ced9e6000f6ee01675f91
MD5 37e6d27cf173b0a6f531f825a57d3f0b
BLAKE2b-256 d59ac41e74b13dd69c76034d687c604d801d123453ad1370a303237a8d404044

See more details on using hashes here.

File details

Details for the file pkg_doctor-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pkg_doctor-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.11

File hashes

Hashes for pkg_doctor-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7d0bbb5cc90857406c969b0029cf74be848f47ea2443c24e0509ba415e25e270
MD5 e464854eb3eca69739d6da5935ccfd7f
BLAKE2b-256 f2b453a71e7e6a9551bf0c73322c1fe187fe4c58bb3f2e6321c860c65a5edfcb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page