Files
graphify/SECURITY.md
T
Safi 41e4e3576a security: SSRF protection, HTML escaping, path guards, encoding hardening
- graphify/security.py (new): centralised security module
    - validate_url(): blocks file://, ftp://, data:, any non-http/https scheme
    - _NoFileRedirectHandler: re-validates redirect targets, blocks file:// redirects
    - safe_fetch(): streams response, 50MB hard cap, non-2xx raises, timeout
    - safe_fetch_text(): safe_fetch + UTF-8 decode with errors=replace
    - validate_graph_path(): resolves path, requires inside .graphify/, base must exist
    - sanitize_label(): strip control chars, cap 256, html.escape() — mirrors
      code-review-graph's _sanitize_name pattern
- graphify/ingest.py: _fetch_html() and _download_binary() now use safe_fetch*;
  ingest() validates URL scheme and wraps network calls in try/except;
  YAML frontmatter: newlines stripped from question before embedding
- graphify/extract.py: all 33 bare .decode() → .decode("utf-8", errors="replace")
  — non-UTF-8 source files degrade gracefully instead of crashing extraction
- graphify/export.py: sanitize_label() on all node labels and edge titles
  before pyvis embeds them in HTML output
- graphify/serve.py: _load_graph() validates graph_path via validate_graph_path()
  and wraps JSONDecodeError with recovery message; sanitize_label() on MCP
  text output
- graphify/detect.py: os.walk(..., followlinks=False) made explicit
- SECURITY.md (new): threat model, mitigations table, reporting process
- tests/test_security.py (new): 20 tests covering all security.py functions
2026-04-04 18:56:38 +01:00

2.9 KiB

Security Policy

Supported Versions

Version Supported
0.1.x Yes
< 0.1 No

Reporting a Vulnerability

Do not open a public GitHub issue for security vulnerabilities.

Report security issues via GitHub's private vulnerability reporting, or email the maintainer directly. Please include:

  • Description of the vulnerability
  • Steps to reproduce
  • Potential impact
  • Suggested fix (if any)

We will acknowledge receipt within 48 hours and aim to release a fix within 7 days for critical issues.

Security Model

graphify is a local development tool. It runs as a Claude Code skill and optionally as a local MCP stdio server. It makes no network calls during graph analysis — only during ingest (explicit URL fetch by the user).

Threat Surface

Vector Mitigation
SSRF via URL fetch security.validate_url() allows only http and https schemes. Redirect targets are re-validated by _NoFileRedirectHandler — a redirect to file:// is blocked.
Oversized downloads safe_fetch() streams responses and aborts at 50 MB. safe_fetch_text() aborts at 10 MB.
Non-2xx HTTP responses safe_fetch() raises HTTPError on non-2xx status codes — error pages are not silently treated as content.
Path traversal in MCP server security.validate_graph_path() resolves paths and requires them to be inside .graphify/. Also requires the .graphify/ directory to exist.
XSS in graph HTML output security.sanitize_label() strips control characters, caps at 256 chars, and HTML-escapes all node labels and edge titles before pyvis embeds them.
Prompt injection via node labels sanitize_label() also applied to MCP text output — node labels from user-controlled source files cannot break the text format returned to agents.
YAML frontmatter injection Newlines stripped from user-provided strings before embedding in YAML frontmatter (e.g. in save_query_result()).
Encoding crashes on source files All tree-sitter byte slices decoded with errors="replace" — non-UTF-8 source files degrade gracefully instead of crashing extraction.
Symlink traversal os.walk(..., followlinks=False) is explicit throughout detect.py.
Corrupted graph.json _load_graph() in serve.py wraps json.JSONDecodeError and prints a clear recovery message instead of crashing.

What graphify does NOT do

  • Does not run a network listener (MCP server communicates over stdio only)
  • Does not execute code from source files (tree-sitter parses ASTs — no eval/exec)
  • Does not use shell=True in any subprocess call
  • Does not store credentials or API keys

Optional network calls

  • ingest subcommand: fetches URLs explicitly provided by the user
  • PDF extraction: reads local files only (pypdf does not make network calls)
  • watch mode: local filesystem events only (watchdog does not make network calls)