Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐍 PyPI
Not in CISA KEV

Langroid: Neo4jChatAgent executes LLM-generated Cypher without validation (prompt-to-Cypher injection; config-conditional RCE), mirroring the SQLChatAgent bug fixed in CVE-2026-25879GHSA-2pq5-3q89-j7cc

GHSA-2pq5-3q89-j7cc is a CWE-74 vulnerability in langroid. A fix is available for langroid — see the affected versions and patch details below.

Also known asCVE-2026-55615PYSEC-2026-2576
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Oct 7, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
  • A successful exploit gives an attacker total control of the affected component, not partial access.

Exploitation and automatability from CISA’s SSVC triage for GHSA-2pq5-3q89-j7cc.

EPSS Exploitation Probability

via FIRST.org ↗
0.5%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs38th percentile — riskier than 38% of all scored CVEsHighest risk
0.00%0.32%0.64%0.96%0.4%0.5%0.5%0.5%Aug 26Oct 26Oct 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

Real-World Exposure

1 pkg affected
🐍langroid

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

Neo4jChatAgent passes LLM-generated Cypher queries straight to the Neo4j driver with no validation, no statement-type allowlist, and no opt-out gate. The query text is influenceable by prompt injection (direct user input or indirect content the agent reads back via RAG), so an attacker who can influence the prompt can read or destroy all graph data and, when APOC or dbms.security procedures are enabled on the server, achieve OS-command and filesystem access. This is the same defect class and threat model as the SQLChatAgent prompt-to-SQL-to-RCE issue fixed in version 0.63.0 (CVE-2026-25879); that fix did not extend to the neo4j module.

Technical detail

Untrusted-input to sink trace (reviewed on langroid HEAD b9df06f, v0.65.3):

  1. Tool schemas accept raw query text from the LLM. langroid/agent/special/neo4j/tools.py:4-9 (CypherRetrievalTool.cypher_query: str) and :15-21 (CypherCreationTool.cypher_query: str). These tools are enabled unconditionally in neo4j_chat_agent.py:412-419 (enable_message([GraphSchemaTool, CypherRetrievalTool, CypherCreationTool, DoneTool])).

  2. Read path. neo4j_chat_agent.py:300 cypher_retrieval_tool(msg) -> :325 query = msg.cypher_query -> :328 self.read_query(query) -> :223 session.run(query, parameters). The LLM-controlled string is the first positional argument to session.run; parameters is None. No validation occurs between :325 and :223.

  3. Write path. neo4j_chat_agent.py:338 cypher_creation_tool(msg) -> :348 query = msg.cypher_query -> :351 self.write_query(query) -> :276 session.write_transaction(lambda tx: tx.run(query, parameters)). The only inspection of the string (write_query :251-264) is a query.upper() substring test for CREATE/MERGE/CONSTRAINT/INDEX whose sole effect is setting self.config.database_created = True; it blocks nothing. A query such as MATCH (n) DETACH DELETE n (the same statement the built-in remove_database helper runs at :287-293) passes unrestricted.

  4. Guarded-sibling contrast proving the incomplete fix. The SQLChatAgent, patched for the parent CVE, validates every query before execution. langroid/agent/special/sql/sql_chat_agent.py:256 defines allow_dangerous_operations: bool = False (opt-in gate); :618 _validate_query runs (a) a dangerous-pattern regex blocklist (_DANGEROUS_SQL_PATTERNS, :628-641), (b) a sqlglot statement-type allowlist defaulting to SELECT-only (:643-686), and (c) an AST-level dangerous-function blocklist (:687-704). run_query calls rejection = self._validate_query(query) at :721 before executing. The neo4j read_query/write_query paths have no equivalent: a grep for _validate_query/allow_dangerous in neo4j_chat_agent.py returns nothing. The defense exists for SQL and is simply absent for Cypher, which is the definition of an incomplete fix for the same prompt-to-query-language injection class.

Proof of concept (static, no third-party systems, no live Neo4j required)

Step 1 (presence vs absence of the guard, one command):

grep -n "_validate_query\|allow_dangerous" langroid/agent/special/sql/sql_chat_agent.py    # SQL: many hits (gate + validator + call site :721)
grep -n "_validate_query\|allow_dangerous" langroid/agent/special/neo4j/neo4j_chat_agent.py # neo4j: ZERO hits

Step 2 (sink trace is direct, no interposed check):

read_query:  msg.cypher_query (line 325) -> read_query(query) (328) -> session.run(query, parameters) (223)
write_query: msg.cypher_query (348) -> write_query(query) (351) -> tx.run(query, parameters) (276)

The only string inspection (write_query 251-264) is a .upper() substring test that only sets database_created=True and rejects nothing. The asymmetry (validator + opt-out gate enforced on every SQL query at sql_chat_agent.py:721; nothing on either Cypher path) is the deterministic artifact: the same project, for the same injection class, guards one query language and not the other. A dynamic confirmation against an operator-owned disposable Neo4j (create a CSPRNG-marked node via cypher_creation_tool, read it back via cypher_retrieval_tool, then DETACH DELETE it) reproduces the read/write/destroy primitive without any third-party system.

Impact

An attacker who can influence the agent prompt (directly, or indirectly via content the agent reads back through RAG) controls the executed Cypher. Floor (no extra config, not contingent): unauthorized read of all graph data via cypher_retrieval_tool and full write/destroy (including MATCH (n) DETACH DELETE n) via cypher_creation_tool, plus the built-in LOAD CSV remote-fetch (SSRF) primitive. Ceiling (config-conditional, when APOC / dbms.security procedures are granted to the DB role, a common deployment): apoc.load.* (SSRF + remote/local file read), apoc.cypher.runFile / apoc.import.* / apoc.export.* (filesystem), and CALL dbms.* admin procedures, i.e. the Cypher analogue of the parent's COPY ... FROM PROGRAM RCE primitive. This mirrors the privileged-role contingency the parent advisory (CVE-2026-25879) accepted.

Suggested fix

Mirror the SQLChatAgent fix in the neo4j module: (1) add allow_dangerous_operations: bool = False to Neo4jChatAgentConfig with a read-only default for cypher_retrieval_tool; (2) add a _validate_cypher(query, write) method that, unless allow_dangerous_operations is True, blocks CALL apoc., CALL dbms., CALL db.* admin procedures, LOAD CSV, and any procedure/function touching filesystem/network/OS, and (for the read path) rejects write clauses (CREATE/MERGE/SET/DELETE/DETACH DELETE/REMOVE/DROP); (3) enforce it before session.run (read_query :223) and tx.run (write_query :276), returning the rejection to the LLM the way run_query does at sql_chat_agent.py:721; (4) document, as the SQL config does, that LLM-generated Cypher is prompt-injectable and that allow_dangerous_operations should only be set with a least-privilege Neo4j role. I am happy to send this as a PR if useful.

Relationship to the parent advisory

GHSA-mxfr-6hcw-j9rq / CVE-2026-25879 (Langroid SQLChatAgent prompt-to-SQL injection leading to RCE; Critical; fixed 0.63.0, SQLChatAgent only). This report is the same injection class in the still-unpatched sibling Neo4jChatAgent.

Severity note (honest, both ways)

Filed as High to reflect the non-contingent floor (unrestricted attacker-steered graph read/write/destroy + LOAD CSV SSRF, present regardless of APOC). The ceiling is Critical and RCE-equivalent when APOC / admin procedures are enabled on the DB role, at parity with the parent CVE-2026-25879 which was rated Critical under an equivalent privileged-role contingency. Please rate per your deployment assumptions.

Resolution (maintainer)

Fixed in 0.65.5. Both Neo4jChatAgent (Cypher) and the sibling ArangoChatAgent (AQL, raised in the follow-up) now mirror the SQLChatAgent controls: a new allow_dangerous_operations config gate (default False), with the retrieval tool restricted to read-only queries and both tools rejecting code-execution / file / network primitives (LOAD CSV, apoc.*, dbms.*, CALL db.* for Cypher; user-defined namespace::func calls for AQL) unless the operator opts in. Validation is enforced at the tool handlers, so internal schema/maintenance calls are unaffected. Upgrade to 0.65.5 and run the agents against a least-privilege database role.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPIlangroidall versions0.65.5pip install --upgrade 'langroid==0.65.5'

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for langroid, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update langroid to 0.65.5 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-2pq5-3q89-j7cc is resolved across your whole dependency graph.

  3. Workarounds

    Until you can upgrade, make sure every query built from user input uses parameterised statements or a prepared-statement API rather than string concatenation, and reduce the database account's privileges so an injected query cannot read or alter data beyond what the feature needs.

Frequently Asked Questions

Neo4jChatAgent passes LLM-generated Cypher queries straight to the Neo4j driver with no validation, no statement-type allowlist, and no opt-out gate. The query text is influenceable by prompt injection (direct user input or indirect content the agent reads back via RAG), so an attacker who can influence the prompt can read or destroy all graph data and, when APOC or dbms.security procedures are enabled on the server, achieve OS-command and filesystem access. This is the same defect class and threat model as the SQLChatAgent prompt-to-SQL-to-RCE issue fixed in version 0.63.0 (CVE-2026-25879); t
O3 Security · Impact-Aware SCA

Is GHSA-2pq5-3q89-j7cc in your dependencies?

Find it across PyPI, including transitive dependencies.

Langroid: Neo4jChatAgent executes LLM-generated…