Skip to main content

Scan local projects for known-vulnerable or malicious dependencies, and get guided help rotating exposed API keys.

Project description

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 - not by guessing at variable names (anyone can name a credential anything), but by surfacing every assignment for you to judge. A value matching a known shape (OpenAI, Anthropic, Google, AWS, GitHub) gets a precise high-confidence label; everything else is still surfaced, just marked low-confidence. 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

Project details


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.1.tar.gz (15.3 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.1-py3-none-any.whl (14.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pkg_doctor-0.1.1.tar.gz
  • Upload date:
  • Size: 15.3 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.1.tar.gz
Algorithm Hash digest
SHA256 9dbd8dcd04c98b14231ecd29627e2e934f9ec31979826a87f5a36ee182207e0b
MD5 df126151fd30f3c9b1d02d4fc2bbb65d
BLAKE2b-256 dffdf2cbe7148ceb9a0584bafd86e736ebe528618ced8d4bfc73e146e5d47924

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pkg_doctor-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 14.7 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 49d92900da70c8c99248134d94efea18acd7d709fc037a3741c4a85ce5c429df
MD5 eceff80038720e45ef0c476214857859
BLAKE2b-256 56895cea94160806991ffafc56896e5259cc5fabbe1e32636f3f299bb4ed98a5

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