Vulnerabilities in pkg:pypi/langroid

PACKAGE
Advisory Identifier: GHSA-2pq5-3q89-j7cc
Advisory Summary

CVE-2026-55615 is a CRITICAL remote code execution vulnerability (CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')) affecting Langroid libraries in the PyPI ecosystem. The issue involves neo4jchatagent executes llm-generated cypher without validation (prompt-to-cypher injection; config-conditional rce), mirroring the sqlchatagent bug fixed in cve-2026-25879. Remediation is available by upgrading affected packages to version 0.65.5.

11 Known Advisory Record(s)
Package Vulnerability Intelligence

pkg:pypi/langroid

11 Known Advisory Record(s)

Vulnerability advisories affecting package pkg:pypi/langroid. Select an advisory below to view technical details or fixes.

Advisory ID CVE / NVD Severity Summary
GHSA-2pq5-3q89-j7cc CVE-2026-55615 CRITICAL Langroid: Neo4jChatAgent executes LLM-generated Cypher without validation (prompt-to-Cypher injection; config-conditional RCE), mirroring the SQLChatAgent bug fixed in CVE-2026-25879
GHSA-gjgq-w2m6-wr5q CVE-2026-54771 HIGH Langroid: handle_message() executes user-supplied tool JSON without sender verification
GHSA-q9p7-wqxg-mrhc CVE-2026-54769 CRITICAL Langroid: Sandbox Escape to Remote Code Execution via Incomplete `eval()` Mitigation in TableChatAgent
GHSA-6xc5-4r68-67fc CVE-2026-54760 CRITICAL Langroid: SQLChatAgent dangerous-function blocklist can be bypassed with quoted or schema-qualified pg_read_file calls
GHSA-pmch-g965-grmr CVE-2026-50180 HIGH Langroid: SQLChatAgent _validate_query blocklist misses pg_read_file family enabling arbitrary file read
GHSA-fg23-3346-88f5 CVE-2026-50181 HIGH Langroid: Path traversal in the file tools allows read/write outside configured current directory
GHSA-mxfr-6hcw-j9rq CVE-2026-25879 CRITICAL Langroid has Prompt to SQL Injection, Leading to RCE
GHSA-x34r-63hx-w57f CVE-2026-25481 CRITICAL Langroid has WAF Bypass Leading to RCE in TableChatAgent
GHSA-jqq5-wc57-f8hj CVE-2025-46724 CRITICAL Langroid has a Code Injection vulnerability in TableChatAgent
GHSA-22c2-9gwg-mj59 CVE-2025-46725 HIGH Langroid has a Code Injection vulnerability in LanceDocChatAgent through vector_store
GHSA-pw95-88fg-3j6f CVE-2025-46726 HIGH Langroid Allows XXE Injection via XMLToolMessage

CVE-2026-55615 at a Glance

CVE Identifier CVE-2026-55615
GHSA Identifier GHSA-2pq5-3q89-j7cc
Severity CRITICAL
CVSS v3.1 Base Score N/A
CWE Classification CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
Affected Product Langroid
Package Ecosystem PyPI
Published Date
Last Updated

How to Fix CVE-2026-55615

To remediate this vulnerability, upgrade all affected Langroid dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

langroid fixed: 0.65.5
pip install langroid>=0.65.5
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show langroid

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-55615, inspect your installed packages using pip:

pip show langroid

Analyze the terminal output to locate any version of Langroid in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.65.5), your application is affected.

Note: The pip show langroid command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection'), where the product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component. In Langroid, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

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.

CVE-2026-55615 Affected Langroid Versions

1 component(s)
Fixed Versions:
0.65.5
Product / Package Ecosystem Affected Versions Fixed Version
langroid
PyPI
< 0.65.5
0.65.5

References

Frequently Asked Questions

What is CVE-2026-55615?
CVE-2026-55615 is a security vulnerability in Langroid involving Neo4jChatAgent executes LLM-generated Cypher without validation (prompt-to-Cypher injection; config-conditional RCE), mirroring the SQLChatAgent bug fixed in CVE-2026-25879 under CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection').
Which Langroid versions are affected?
Affected versions include releases prior to 0.65.5 across affected packages: langroid.
What version fixes CVE-2026-55615?
Upgrading to 0.65.5 (or the latest patched release for your respective branch) resolves the vulnerability.
Is langroid affected?
Yes, langroid is affected in releases prior to 0.65.5. Upgrade your dependency to 0.65.5 or later.
What CWE is associated with CVE-2026-55615?
CVE-2026-55615 is classified under CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection') (The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.).
How can I check PyPI dependencies for CVE-2026-55615?
Run the dependency tree command: 'pip show langroid'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-2pq5-3q89-j7cc",
  "modified" : "2026-07-06T21:22:43Z",
  "published" : "2026-07-06T21:22:43Z",
  "aliases" : [ "CVE-2026-55615" ],
  "summary" : "Langroid: Neo4jChatAgent executes LLM-generated Cypher without validation (prompt-to-Cypher injection; config-conditional RCE), mirroring the SQLChatAgent bug fixed in CVE-2026-25879",
  "details" : "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.\n\n## Technical detail\nUntrusted-input to sink trace (reviewed on langroid HEAD b9df06f, v0.65.3):\n\n1. 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])).\n\n2. 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.\n\n3. 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.\n\n4. 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.\n\n## Proof of concept (static, no third-party systems, no live Neo4j required)\nStep 1 (presence vs absence of the guard, one command):\n```\ngrep -n \"_validate_query\\|allow_dangerous\" langroid/agent/special/sql/sql_chat_agent.py    # SQL: many hits (gate + validator + call site :721)\ngrep -n \"_validate_query\\|allow_dangerous\" langroid/agent/special/neo4j/neo4j_chat_agent.py # neo4j: ZERO hits\n```\nStep 2 (sink trace is direct, no interposed check):\n```\nread_query:  msg.cypher_query (line 325) -> read_query(query) (328) -> session.run(query, parameters) (223)\nwrite_query: msg.cypher_query (348) -> write_query(query) (351) -> tx.run(query, parameters) (276)\n```\nThe 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.\n\n## Impact\nAn 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.\n\n## Suggested fix\nMirror 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.\n\n## Relationship to the parent advisory\nGHSA-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.\n\n## Severity note (honest, both ways)\nFiled 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.\n\n## Resolution (maintainer)\n\nFixed 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.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "langroid"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.65.5"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 0.65.4"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/langroid/langroid/security/advisories/GHSA-2pq5-3q89-j7cc"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/langroid/langroid"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-74" ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-07-06T21:22:43Z",
    "nvd_published_at" : null
  }
}