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)
LD112 Known CVEs medium Unsafe URL path construction in the LangGraph SDK
LD113 Known CVEs high Template injection via attribute access in prompt templates
LD114 Known CVEs medium Path traversal and sandbox escape in file-search middleware
LD115 Known CVEs low SSRF via image_url token counting
LD116 Known CVEs medium Incomplete f-string validation in prompt templates
LD117 Known CVEs high Unsafe deserialization via overly broad load() allowlists
LD118 Known CVEs medium Namespace prefix matching crosses segments (SQLite store)
LD119 Known CVEs medium Namespace prefix matching crosses segments (Postgres store)
LD120 Known CVEs high 🔴KEV CORS + SameSite token hijack → account takeover (Langflow)
LD121 Known CVEs critical 🔴KEV Unauthenticated RCE via exec_globals in validate (Langflow)
LD122 Known CVEs critical 🔴KEV Unauthenticated RCE via build_public_tmp flow data (Langflow)
LD123 Known CVEs high 🔴KEV IDOR in /api/v1/responses runs another user's flow (Langflow)
LD124 Known CVEs critical 🔴KEV auto_login + validate/code chain → unauth RCE (Langflow)
LD125 Known CVEs critical SSRF via unrestricted OpenAPI RequestsToolkit (community)
LD126 Known CVEs high XXE in EverNoteLoader via unguarded iterparse() (community)
LD127 Known CVEs high SSRF via nested sitemap entries in SitemapLoader (community)
LD150 Known CVEs high Langflow older than the current secure baseline (1.11.0)
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.

A finding can arrive without a fix line. Some advisories have no released fix — LD127 is patched upstream but no langchain-community release carries it yet — and langdoctor reports those as affected with no upgrade to recommend rather than inventing a version or staying quiet.

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.5.tar.gz (903.2 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.5-py3-none-any.whl (40.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: langdoctor-0.1.5.tar.gz
  • Upload date:
  • Size: 903.2 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.5.tar.gz
Algorithm Hash digest
SHA256 5394ddb7120519e155c068a0fcd9e46dad9f29838f315a1f85acb81e6c3d2076
MD5 297a6a3b8b85f42630e6629ec77535f3
BLAKE2b-256 593b8d1ec9766d00c6df52bb3a96951f9a2b56b295eb0e8ad50c91a44af95e36

See more details on using hashes here.

Provenance

The following attestation bundles were made for langdoctor-0.1.5.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.5-py3-none-any.whl.

File metadata

  • Download URL: langdoctor-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 40.6 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.5-py3-none-any.whl
Algorithm Hash digest
SHA256 18e0046c2ae0ee128590808553ce173abf021de8f787fb94836f838c7243ea37
MD5 b79d68cd93b62f54b2c2a25178f867c6
BLAKE2b-256 f8ec8cb6acec0902ec0e0baebd895416f038bfff48295d5d74962fa0e84b6ff9

See more details on using hashes here.

Provenance

The following attestation bundles were made for langdoctor-0.1.5-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

This release

0.1.5 This release

2 files

0.1.4

2 files

0.1.3

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