Skip to main content

langdoctor 🩺

Scan your LangGraph/LangChain project for known CVEs, insecure configs, and production footguns — in seconds, offline, no API key.

brew doctor for your agent stack.

PyPI Python CI License: MIT

langdoctor scanning a vulnerable project

Quickstart

pipx run langdoctor        # or: uvx langdoctor

Run it in your project directory. langdoctor reads your dependency files and source, reports issues grouped by severity, and exits non-zero when it finds something at or above your threshold.

langdoctor                 # scan the current directory
langdoctor path/to/project # scan a specific directory
langdoctor list-checks     # every check, with IDs and severities
langdoctor --version       # tool version + advisory DB date

Why

2026 has been a rough year for the agent stack:

  • Langflow is under active attack. CVE-2025-3248 (unauthenticated RCE) was added to the CISA KEV catalog and exploited to deploy the Flodrix botnet; CVE-2026-5027 (path-traversal → RCE) is being exploited across ~7,000 exposed instances.
  • LangGraph checkpointer CVEs — SQL injection and unsafe deserialization in the SQLite/base checkpointers can chain to RCE via forged checkpoint rows.
  • Supply-chain attacks on the CI actions and packages the ecosystem depends on (the tj-actions and LiteLLM incidents) mean a pinned-to-a-tag action or an unpinned dependency is a real risk surface.

These are exactly the things a framework-specific linter can catch before you ship. langdoctor ships the CVE data with the package and runs fully offline.

What it checks

ID Category Severity What it catches
LD101 Known CVEs high SQL injection via metadata filter key in SQLite checkpointer
LD102 Known CVEs medium Unsafe msgpack deserialization in checkpoint loading
LD103 Known CVEs medium Unsafe JSON deserialization in checkpoint loading
LD104 Known CVEs high Path traversal in legacy load_prompt functions
LD105 Known CVEs critical Serialization-injection secret extraction in dumps/loads
LD106 Known CVEs critical 🔴KEV Unauthenticated RCE in /api/v1/validate/code (Langflow)
LD107 Known CVEs medium BaseCache deserialization of untrusted data may lead to RCE
LD108 Known CVEs high RCE in "json" mode of JsonPlusSerializer
LD109 Known CVEs high SQL injection in the SQLite store implementation
LD110 Known CVEs high SQL injection via filter key in SqliteStore
LD111 Known CVEs high 🔴KEV Path traversal → RCE via /api/v2/files upload (Langflow)
LD150 Known CVEs high Langflow older than the current secure baseline (1.10.1)
LD201 Checkpointer & state high MemorySaver used in a production-bound project
LD202 Checkpointer & state medium SqliteSaver may collapse under write concurrency
LD203 Checkpointer & state high (heuristic) Checkpoint history filtered by user-controlled input
LD204 Checkpointer & state medium Compiled graph with interrupts has no checkpointer
LD301 Graph & runtime config medium No recursion_limit configured for a LangGraph run
LD302 Graph & runtime config low (heuristic) LLM client created without a timeout
LD303 Graph & runtime config info Deprecated pre-1.0 LangChain import
LD304 Graph & runtime config high Legacy load_prompt() usage
LD401 Secrets & exposure critical Hardcoded API key in source
LD402 Secrets & exposure high .env file present but not gitignored
LD403 Secrets & exposure critical Langflow auto-login not explicitly disabled
LD501 Hygiene medium Dependencies are not pinned
LD502 Hygiene medium GitHub Actions uses an unpinned third-party action

Severities for CVE checks are derived from the CVSS score; 🔴KEV marks Known-Exploited vulnerabilities, which are always surfaced first.

CI integration

GitHub Action

# .github/workflows/langdoctor.yml
name: langdoctor
on: [push, pull_request]
permissions:
  contents: read
  security-events: write   # to upload SARIF
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: elaz48/langdoctor@v1
        with:
          fail-on: high
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: langdoctor.sarif

Findings show up in your repo's Security → Code scanning tab.

pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/elaz48/langdoctor
    rev: v0.1.0
    hooks:
      - id: langdoctor

GitLab CI

langdoctor:
  image: python:3.12-slim
  script:
    - pip install langdoctor
    - langdoctor --format sarif > gl-langdoctor.sarif
  artifacts:
    reports:
      sast: gl-langdoctor.sarif

Configuration

Configure defaults in pyproject.toml; command-line flags take precedence.

[tool.langdoctor]
fail-on = "high"            # critical | high | medium | low | never
ignore  = ["LD203", "LD302"]
exclude = ["examples", "vendor"]

Suppress a single finding inline — by LD id, CVE, or any alias:

API_KEY = get_key()  # langdoctor: ignore=LD401
langgraph==1.0.5  # langdoctor: ignore=LD102

Suppressed findings are always reported as a suppressed: N count so nothing disappears silently.

Output formats

--format console (default) · json · sarif · markdown

  • sarif — GitHub code scanning; security-severity carries the real CVSS.
  • markdown — paste straight into a PR or issue.
  • json — machine-readable, with a per-severity summary.

Exit codes: 0 clean (or below --fail-on), 1 findings at/above threshold, 2 scan error. Heuristic checks never affect the exit code unless --strict.

What langdoctor is NOT

  • Not a runtime guard. It scans code and dependencies; it does not sit in your request path.
  • Not an LLM firewall. It does no prompt-injection or content analysis.
  • Not a replacement for Semgrep/Snyk. It's the framework-specific layer those miss — LangGraph/LangChain/Langflow footguns, by ID, with fixes.

It is deterministic (no AI calls), offline (CVE data ships in the package), and zero-config.

Development

pip install -e ".[dev]"
pytest
ruff check .

Requires Python 3.10+. See CLAUDE.md for design principles, the check-ID conventions, and the "advisories are data" model.

License

MIT © 2026 elaz48

Topics: langgraph · langchain · langflow · security · sast · ai-agents · llm-security · devsecops · cli

Download files

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

Source Distribution

langdoctor-0.1.3.tar.gz (890.7 kB view details)

Uploaded Source

Built Distribution

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

langdoctor-0.1.3-py3-none-any.whl (37.1 kB view details)

Uploaded Python 3

File details

Details for the file langdoctor-0.1.3.tar.gz.

File metadata

  • Download URL: langdoctor-0.1.3.tar.gz
  • Upload date:
  • Size: 890.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for langdoctor-0.1.3.tar.gz
Algorithm Hash digest
SHA256 1a940d345fc8d8bb41c4686bbbc336fa1a87057e1ee1891155b5c0c0f213682d
MD5 7e0afdea6483504fb6019e515829dd27
BLAKE2b-256 35540074a3dd5d489f67c02fefee48be98e1c3505d6a5249d5567f2dc6af4b8a

See more details on using hashes here.

Provenance

The following attestation bundles were made for langdoctor-0.1.3.tar.gz:

Publisher: release.yml on elaz48/langdoctor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file langdoctor-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: langdoctor-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 37.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for langdoctor-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 b8eed6923b66ac2b1541965093cf0802053a07c721d0f8ad9a5bbc10ffd5e3cd
MD5 d2e3c7c3a7e751e534e5c2e25a5619ea
BLAKE2b-256 fbd3cd53ba9a16daee8b06804ff49ca76aeabda00e22563f98fe2b1d97f5edcc

See more details on using hashes here.

Provenance

The following attestation bundles were made for langdoctor-0.1.3-py3-none-any.whl:

Publisher: release.yml on elaz48/langdoctor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.5

2 files

0.1.4

2 files

This release

0.1.3 This release

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page