mirror of
https://github.com/safishamsi/graphify.git
synced 2026-07-14 11:27:10 +00:00
41e4e3576a
- 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
2.9 KiB
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=Truein any subprocess call - Does not store credentials or API keys
Optional network calls
ingestsubcommand: 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)