GHSA-pcc4-rvhr-2pr8Medium▾ SunlitGraphify Fortran extractor: incomplete cpp #include hardening allows arbitrary host-file read/exfiltration when indexing an untrusted repo
▾ Sunlit zone — Low / medium · no exploitation signal
impact 27.5 · likelihood 0 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
The Fortran extractor's C-preprocessor step (graphify/extractors/fortran.py, _cpp_preprocess) applies an incomplete #include hardening. The -nostdinc -I /dev/null flags it relies on (comment "Security (F-007)") do not stop a capital-F Fortran source file from including absolute paths (#include "/etc/passwd") or from path-traversing out of the corpus (#include "../../../../home/victim/.ssh/id_rsa"). cpp always searches the directory of the file being preprocessed for quoted includes and always honours absolute include paths, regardless of -nostdinc/-I. As a result, indexing an untrusted repository that contains a .F/.F90/.F95/.F03/.F08 file reads arbitrary local files off the host and inlines their contents into the knowledge graph, which is then shipped to the LLM/agent and written to the on-disk, shareable output (graph.json, GRAPH_REPORT.md, the Obsidian wiki, HTML/SVG exports).
This is the exact "corpus-side file-exfiltration vector" the F-007 comment says it is defending against; the mitigation is bypassable.
High. Arbitrary local-file read on the host, triggered by graphify's core action (indexing an untrusted folder — "turn any folder of code ... into a queryable knowledge graph"), defeating a documented security control. It runs on the default, offline, no-API-key AST path (graphify update . / graphify extract) — no credentials, network, or LLM call required. CWE-73 (external control of file name/path) / CWE-22 (path traversal) / CWE-200 (information exposure).
graphify/extractors/fortran.py, _cpp_preprocess():
result = subprocess.run(
["cpp", "-w", "-P", "-nostdinc", "-I", "/dev/null", str(path.resolve())],
capture_output=True, timeout=30,
)
Reached from extract_fortran() (same file) for any suffix in _FORTRAN_CPP_EXTS = {".F", ".F90", ".F95", ".F03", ".F08"}, which are collected by default (detect.CODE_EXTENSIONS) and dispatched by extract._DISPATCH.
-nostdinc only removes the standard system include directories, and -I /dev/null only sets the additional search path. Neither affects:
#include "/etc/passwd" is opened directly by cpp.#include "...", so #include "../../../../etc/shadow" traverses out of the corpus.Reproduced against the shipped code with the exact command _cpp_preprocess builds (cpp -w -P -nostdinc -I /dev/null <file>), and against extract_fortran() directly.
Secret on disk (/tmp/secret.txt): TOP_SECRET_...
(a) Absolute include — evil_abs.F90:
program evil
#include "/absolute/path/to/secret.txt"
end program evil
(b) Relative traversal — evil_rel.F90:
program evil
#include "../secret.txt"
end program evil
Both produce preprocessed output containing the full secret file contents ("SECRET IN OUTPUT: True" for both).
Surfacing into the graph — leak.F90 places the include in an identifier position via a free-form continuation so the leaked value becomes a node/edge:
module m
contains
subroutine s
use &
#include "/path/to/token.secret"
end subroutine s
end module m
extract_fortran() on this file emits a node whose label is the entire single-line contents of token.secret and an imports edge to it. That node is written to graph.json / GRAPH_REPORT.md / the wiki and returned by the MCP query_graph / get_node / get_neighbors tools — i.e. exfiltrated into the agent's context and into persisted, shareable artifacts.
Fidelity note: Fortran is case-insensitive, so captured identifiers are lower-cased. Case-insensitive secrets (file paths, hostnames, usernames, hex tokens, connection-string fragments, and the mere existence/partial content of a readable file) leak cleanly; high-entropy case-sensitive blobs (base64/JWT) are partially corrupted by the lower-casing but still confirm readability and structure. Single-token-per-line secret files (API-key files, single-line credential/token files) leak that token in full (lower-cased). Requires cpp/gcc on PATH (near-ubiquitous on the dev/CI hosts graphify targets); it cleanly falls back to raw bytes when absent.
Mirror the containment approach already used elsewhere in the codebase (_project_xml_is_safe, security.validate_graph_path): before invoking cpp, scan the source for #include directives and refuse or neutralise any include whose target is absolute or resolves outside the corpus/repo root. Concretely, in _cpp_preprocess:
#include "..." / #include <...> directives..resolve() escapes the scan root, strip that line (or fall back to path.read_bytes() with no preprocessing).A blunter but safe alternative is to strip all #include lines before preprocessing (macros still expand; cross-file includes lose fidelity but no host files can be read). Running cpp inside a filesystem sandbox (bwrap/unshare with only the corpus mounted) would also close it but is heavier.
Aeon vuln-scanner. Semgrep flagged the Fortran subprocess path; manual review of the F-007 mitigation plus an empirical cpp repro confirmed the bypass.
graphifyy >= 0.7.2, < 0.9.70Upgrade to a patched release:
graphifyy 0.9.70Connected by shared product, vendor, weakness, or advisory.
CVE-2022-37906Medium· 6.5An authenticated path traversal vulnerability exists in the ArubaOS command line interface
CVE-2024-13986High· 8.8Nagios XI < 2024R1.3.2 contains a remote code execution vulnerability by chaining two flaws: an arbitrary file upload and a path traversal in the Core Config Snapshots interface
CVE-2024-13984NoneQiAnXin TianQing Management Center versions up to and including 6.7.0.4130 contain a path traversal vulnerability in the rptsvr component that allows unauthenticated attackers to upload files to arbitrary locations on the server
CVE-2023-7260High· 7.5Path Traversal vulnerability discovered in OpenText™ CX-E Voice, affecting all version through 22.4
CVE-2023-7249Critical· 9.8Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability in OpenText OpenText Directory Services allows Path Traversal.This issue affects OpenText Directory Services: from 16.4.2 before 24.1.
CVE-2020-3365Medium· 4.3A vulnerability in the directory permissions of Cisco Enterprise NFV Infrastructure Software (NFVIS) could allow an authenticated, remote attacker to perform a directory traversal attack on a limited set of restricted directories