mirror of
https://github.com/safishamsi/graphify.git
synced 2026-07-12 10:27:11 +00:00
fix MCP server path validation security issue (0.3.26)
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
Full release notes with details on each version: [GitHub Releases](https://github.com/safishamsi/graphify/releases)
|
||||
|
||||
## 0.3.26 (2026-04-10)
|
||||
|
||||
- Fix: MCP server no longer uses a circular path validation when loading a graph outside cwd — now validates the path exists and ends in `.json` instead of checking containment within its own parent directory (security fix)
|
||||
|
||||
## 0.3.25 (2026-04-09)
|
||||
|
||||
- Fix: `graphify install --platform gemini` now routes to `gemini_install()` instead of erroring — `gemini` was missing from `_PLATFORM_CONFIG` (#171)
|
||||
|
||||
+7
-2
@@ -5,12 +5,17 @@ import sys
|
||||
from pathlib import Path
|
||||
import networkx as nx
|
||||
from networkx.readwrite import json_graph
|
||||
from graphify.security import validate_graph_path, sanitize_label
|
||||
from graphify.security import sanitize_label
|
||||
|
||||
|
||||
def _load_graph(graph_path: str) -> nx.Graph:
|
||||
try:
|
||||
safe = validate_graph_path(graph_path, base=Path(graph_path).resolve().parent)
|
||||
resolved = Path(graph_path).resolve()
|
||||
if resolved.suffix != ".json":
|
||||
raise ValueError(f"Graph path must be a .json file, got: {graph_path!r}")
|
||||
if not resolved.exists():
|
||||
raise FileNotFoundError(f"Graph file not found: {resolved}")
|
||||
safe = resolved
|
||||
data = json.loads(safe.read_text())
|
||||
try:
|
||||
return json_graph.node_link_graph(data, edges="links")
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "graphifyy"
|
||||
version = "0.3.25"
|
||||
version = "0.3.26"
|
||||
description = "AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, OpenClaw, Factory Droid, Trae) - turn any folder of code, docs, papers, or images into a queryable knowledge graph"
|
||||
readme = "README.md"
|
||||
license = { file = "LICENSE" }
|
||||
|
||||
+1
-4
@@ -138,14 +138,11 @@ def test_subgraph_to_text_edge_included():
|
||||
# --- _load_graph ---
|
||||
|
||||
def test_load_graph_roundtrip(tmp_path):
|
||||
from unittest.mock import patch
|
||||
G = _make_graph()
|
||||
data = json_graph.node_link_data(G, edges="links")
|
||||
p = tmp_path / "graph.json"
|
||||
p.write_text(json.dumps(data))
|
||||
# validate_graph_path is tested separately; here we test parse correctness
|
||||
with patch("graphify.serve.validate_graph_path", return_value=p):
|
||||
G2 = _load_graph(str(p))
|
||||
G2 = _load_graph(str(p))
|
||||
assert G2.number_of_nodes() == G.number_of_nodes()
|
||||
assert G2.number_of_edges() == G.number_of_edges()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user