On this page · 13 sections
- What actually broke
- How the chain works
- Which deployments are actually exposed
- The 30-minute audit
- Hardening past the patch
- Two escape hatches that silently disable the fix
- Detection: what to look for in logs
- Why the "moderate" rating is misleading
- Where this fits in your agent threat model
- India-specific considerations
- FAQ
- How eCorpIT can help
- References
Summary. Three now-patched LangGraph flaws let an attacker walk from a metadata filter string to code execution on a self-hosted agent server. Check Point researcher Yarden Porat reported all three: CVE-2025-67644 (CVSS 7.3, SQL injection in the SQLite checkpointer), CVE-2026-28277 (CVSS 6.8, unsafe msgpack deserialization in LangGraph itself) and CVE-2026-27022 (CVSS 6.5, RediSearch query injection in the JavaScript Redis checkpointer). The first two chain. The Hacker News published the details on 12 June 2026; the msgpack advisory, GHSA-g48c-2wqr-h844, went to the GitHub Advisory Database on 5 March 2026 with CWE-502 and an EPSS score of 0.332%. Fixed versions are langgraph-checkpoint-sqlite 3.0.1, langgraph 1.0.10 and @langchain/langgraph-checkpoint-redis 1.0.2. LangChain's managed LangSmith Deployment is not affected.
The reason this matters more than the CVSS numbers suggest: Check Point's 2026 Cloud Security Report found 64% of organisations already have AI agents in pilot or production and 12% have granted those agents privileged access to core systems. An agent runtime holds LLM API keys, database credentials and conversation state. In India, personal data sitting in that state is squarely inside the Digital Personal Data Protection Act 2023, where the Data Protection Board can levy up to ₹250 crore (about $26 million) per major violation. A checkpoint table is not a cache. It is a credential-adjacent datastore that your application deserialises into live Python objects.
What actually broke
LangGraph persists agent state as checkpoints. Every superstep writes a serialised snapshot of the graph's channels to whatever backing store you configured, and get_state_history() reads them back so an agent can resume, branch or replay a thread. The three flaws sit at two different layers of that path: the query that finds a checkpoint, and the decoder that turns its bytes back into objects.
CVE-2025-67644: SQL injection through metadata filter keys
The SQLite checkpointer's _metadata_predicate() builds its WHERE clause with f-string interpolation. User-supplied metadata filter keys land directly in the SQL text, including inside json_extract expressions, with no parameterisation and no escaping. Any application that passes an untrusted filter dictionary into a checkpoint search hands the attacker query control. GitLab's advisory database records the affected range as langgraph-checkpoint-sqlite 3.0.0 and below, fixed in 3.0.1, carrying a CVSS score of 7.3 under GHSA-9rwj-6rc7-p77c.
On its own, this leaks. An attacker bypasses the thread filter and reads every checkpoint row in the table: other users' conversation state, thread identifiers, whatever metadata your graph writes. For a multi-tenant agent that is already a reportable incident.
CVE-2026-28277: msgpack deserialisation that rebuilds arbitrary Python objects
LangGraph's JsonPlusSerializer encodes checkpoints as msgpack, and its decoder handles extension types by reconstructing Python objects. The GitHub advisory describes the pattern as equivalent to getattr(importlib.import_module(module_name), callable_name)(arguments). Any importable callable, invoked with attacker-supplied arguments. That includes os.system and subprocess.Popen.
The advisory rates it Moderate at 6.8, with the vector CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H, and is explicit that it is a defence-in-depth issue: exploitation requires the ability to write attacker-controlled checkpoint bytes at rest. Affected versions are langgraph 1.0.9 and below; the fix shipped in 1.0.10 on 5 March 2026. LangGraph's own note says there is no evidence of exploitation in the wild.
CVE-2026-27022: RediSearch query injection in the JavaScript checkpointer
The RedisSaver and ShallowRedisSaver classes in @langchain/langgraph-checkpoint-redis interpolate user-provided filter keys and values straight into RediSearch queries. RediSearch treats characters like @, |, -, *, ( and ) as syntax, so an attacker who controls a filter value can rewrite the query logic and bypass the access controls that were supposed to scope results to one thread. It is CWE-74, CVSS 6.5, vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N, published to NVD on 20 February 2026 under GHSA-5mx2-w598-339m. The fix, in pull request 1943, adds an escapeRediSearchTagValue utility and also hardens the MongoDB checkpoint path by rejecting non-primitive filter values, which closes a parallel MongoDB operator-injection hole.
One version discrepancy worth knowing before you write a ticket. The Hacker News, citing the GitHub advisory, gives the affected range as versions before 1.0.1. SentinelOne's vulnerability database and the linked release tag both point at 1.0.2. Pin 1.0.2 or later and the argument goes away.
How the chain works
Read the second and third bullets slowly, because this is where a "requires privileged write access" advisory quietly stops requiring privileged write access.
- The attacker builds a msgpack payload whose extension type names a dangerous callable and its arguments.
- The attacker sends a malicious filter parameter to an endpoint that reaches
get_state_history(), exploiting CVE-2025-67644 so the SQL query returns a fabricated checkpoint row whosecheckpointcolumn contains that payload.
- The application processes the result set and deserialises the BLOB.
- CVE-2026-28277 reconstructs the attacker's object. The payload runs inside the agent runtime.
The attacker never needed write access to the database. The SQL injection manufactures the row inside the query result. That is the whole trick, and it is why triaging CVE-2026-28277 in isolation as "post-exploitation only" gets the priority wrong on any deployment that also runs an unpatched SQLite checkpointer with user-influenced filters.
Check Point's write-up puts the exposure boundary plainly: the chain is exploitable in self-hosted deployments using the SQLite or Redis checkpointer with user-controlled filter input, and LangChain's managed platform is not affected.
Which deployments are actually exposed
Most teams do not know which checkpointer their staging cluster is running, because it was chosen in week one of a prototype and never revisited. Start here.
| Checkpointer backend | Affected by | Minimum safe version | What to check first |
|---|---|---|---|
langgraph-checkpoint-sqlite (Python) |
CVE-2025-67644 and CVE-2026-28277 | 3.0.1, plus langgraph 1.0.10 |
Whether any HTTP handler passes a request-derived dict into a checkpoint search |
@langchain/langgraph-checkpoint-redis (JS) |
CVE-2026-27022 | 1.0.2 | Filter values reaching RedisSaver or ShallowRedisSaver without escaping |
| MongoDB checkpoint (JS) | Operator injection hardened in the same patch | Ship with the 1.0.2 release train | Filter values that are objects rather than primitives |
| PostgreSQL checkpointer | Not named in these three advisories | Current langgraph 1.0.10 |
Still patch langgraph itself for the msgpack decoder |
| In-memory / no persistence | Not exposed via a store | Current langgraph |
Nothing persists, but review any custom serializer hooks |
| LangSmith Deployment (managed) | Not affected | Managed by LangChain | Confirm you are genuinely on the managed plane, not a self-hosted copy |
The row that catches people is PostgreSQL. Teams read "SQLite and Redis" and close the ticket. The msgpack decoder lives in langgraph, not in the SQLite package, so a Postgres-backed deployment on langgraph 1.0.9 still deserialises checkpoints unsafely. It simply lacks the SQL injection that would let an unauthenticated caller forge a row. If your Postgres credentials leak, or a batch job with write access is compromised, the deserialisation path is right there.
The 30-minute audit
Run this against every environment that resumes agent state, including the staging cluster nobody owns. Each step is a single command and a pass criterion.
| Step | Command | Pass criterion | ||
|---|---|---|---|---|
| 1. Inventory Python packages | `pip list \ | grep -Ei "langgraph\ | langchain"` | langgraph at 1.0.10 or later |
| 2. Inventory the SQLite checkpointer | pip show langgraph-checkpoint-sqlite |
Version 3.0.1 or later, or the package is absent | ||
| 3. Inventory the JS checkpointer | npm list @langchain/langgraph-checkpoint-redis |
Version 1.0.2 or later, or the package is absent | ||
| 4. Find untrusted filter paths | `grep -rn "get_state_history\ | aget_state_history" --include=*.py .` | Every call site takes a server-constructed filter, never a raw request body | |
| 5. Check the JS filter paths | `grep -rn "RedisSaver\ | ShallowRedisSaver" --include=.ts --include=.js .` | Filter values are escaped or allowlisted before the call | |
| 6. Confirm strict mode | `env \ | grep LANGGRAPH_STRICT_MSGPACK` | Set to true in every production environment |
|
| 7. Look for custom decoder hooks | `grep -rn "ext_hook\ | JsonPlusSerializer(" --include=*.py .` | No custom ext_hook, or one with an explicit allowlist |
|
| 8. Review store write access | List IAM principals and service accounts with write on the checkpoint store | Only the agent runtime and one break-glass role |
Steps 4 and 5 are the ones that decide your severity. If no user-controlled string reaches a filter key, you have a patching task. If one does, and you are below the fixed versions, you have an incident-response task and the order of operations changes: contain first, rotate the credentials the runtime can reach, then patch.
Hardening past the patch
Upgrading closes the injection. It does not, by itself, stop the decoder from rebuilding arbitrary types, because the default policy after the patch is still permissive. LangGraph shipped an allowlist mechanism alongside the fix, and it has three states.
Setting for allowed_msgpack_modules |
Behaviour | When to use it |
|---|---|---|
True (default when strict mode is off) |
Reconstructs all extension types, logs a warning for unregistered ones | Local development only |
None (strict) |
Reconstructs only the built-in safe set, blocks everything else | Production default, once you have read the warnings from a staging run |
[(module, class_name), ...] |
Built-in safe set plus exactly the listed symbols, matched exactly | Production, when strict mode breaks a legitimate custom type |
Setting the environment variable LANGGRAPH_STRICT_MSGPACK to a truthy value (1, true or yes) flips JsonPlusSerializer() to default allowed_msgpack_modules to None instead of True, unless you passed the argument explicitly.
The built-in safe set covers what most graphs actually persist: datetime types, uuid.UUID, decimal.Decimal, set, frozenset, deque, ipaddress types, pathlib paths, zoneinfo.ZoneInfo, compiled regular expressions and selected LangGraph internal types. When strict mode is on and you compile a StateGraph, LangGraph walks your state, input, output and context schemas plus node and branch input schemas and channel value types, and derives an allowlist automatically. It picks up Pydantic v1 and v2 models, dataclasses, enums, TypedDict field types and common typing constructs, plus a curated set of LangChain message classes.
# Patch the Python side
pip install --upgrade "langgraph>=1.0.10" "langgraph-checkpoint-sqlite>=3.0.1"
# Patch the JavaScript side
npm install @langchain/langgraph-checkpoint-redis@^1.0.2
npm list @langchain/langgraph-checkpoint-redis
# Turn on strict deserialisation in every non-local environment
export LANGGRAPH_STRICT_MSGPACK=true
Roll strict mode out in staging first and read the logs. The permissive default warns on every unregistered extension type it reconstructs, which gives you a free inventory of exactly what your graphs serialise before you start blocking anything.
Two escape hatches that silently disable the fix
Both are documented in the advisory, and both are easy to hit by accident.
The first: allowlist enforcement is applied by the checkpointer, through a with_allowlist(...) method. A checkpointer implementation that does not provide it skips enforcement and emits a warning. If you wrote your own saver, or you are using a community backend, strict mode may be doing nothing at all. Verify rather than assume.
The second: if your application supplies a custom msgpack unpack hook via ext_hook, that hook controls reconstruction and bypasses the default allowlist checks entirely. The advisory calls this an intentional escape hatch. It is also exactly the kind of code somebody adds to make one stubborn type round-trip, three sprints before the audit.
A third failure mode is not in the advisory but shows up in practice: constructing serializers or checkpointers manually rather than letting StateGraph.compile() wire them up. The derived allowlist only applies when LangGraph compiles the graph and the checkpointer supports propagation. Hand-built object graphs get the default policy.
Detection: what to look for in logs
You cannot retroactively prove nothing happened, but you can look in three places.
For the SQLite path, search application logs for filter keys containing SQL metacharacters, quotes, json_extract, UNION or comment markers, and for checkpoint searches that returned unusually large result sets. For the Redis path, look for filter values containing RediSearch syntax characters (@, |, -, *, (, ), {, }, [, ], backslash) and enable verbose Redis query logging so the executed queries are actually recoverable. Redis slow-query logs are useful here because injected queries tend to be structurally odd.
For the deserialisation path, the permissive default's own warnings are the signal. Every reconstruction of an unregistered extension type gets logged. If you have those logs from before the patch, grep them for module names that are not in your application's dependency tree.
At the infrastructure layer, treat the checkpoint store as integrity-sensitive. Restrict write access to the runtime itself, rotate credentials if compromise is suspected, and log every principal that has ever written to it. This is the same posture we argue for in enterprise AI agent governance layers: the agent's blast radius is the union of everything its credentials can reach, and the checkpoint store is inside that union.
Why the "moderate" rating is misleading
CVE-2026-28277 scores 6.8 with an EPSS probability of 0.332%, which sits at the 56th percentile. Read alone, that is a patch-next-cycle number. Read as the second half of a chain that starts with a 7.3 SQL injection reachable from an HTTP parameter, it is not.
This is a recurring pattern with agent frameworks rather than a LangGraph-specific failure. Check Point's conclusion was that classic vulnerability classes become more potent inside AI agent frameworks because those frameworks carry elevated access and trust. The framework holds provider API keys, database handles and tool credentials in one process. A bug class that would be a data-leak in a CRUD service becomes credential exfiltration in an agent runtime.
Lotem Finkelstein, VP, Check Point Research, framed the broader shift in the firm's AI Security Report 2026: "The expertise barrier that separated capable attackers from the rest is disappearing, and defenders can no longer assume a human is setting the pace on the other side. The organizations that stay ahead will be the ones that govern how AI is used, secure the AI systems they now depend on, and defend at machine speed rather than human speed."
The same report found that between October 2025 and May 2026, 87% to 93% of organisations experienced at least one high-risk AI interaction every month. Check Point's 2026 Cloud Security Report puts the governance gap in one figure: 77% of organisations have updated their cloud security strategy in response to AI, but only 26% say they have the architecture to enforce it, a 51-point spread between intent and capability.
Check Point's own remediation guidance for this chain goes past the version bump: put authentication in front of self-hosted LangGraph servers, avoid long-lived static secrets, enforce network segmentation, treat AI agents as privileged identities, and apply least privilege to the agent's access footprint. That last point is the durable one. The framework you pick matters less than the credentials you hand it, which is the argument we made when comparing AI agent frameworks for production.
Where this fits in your agent threat model
Prompt injection gets the attention because it is novel. This chain is a reminder that the boring half of the attack surface is still there: an ORM-free f-string, a permissive deserialiser, an endpoint that trusts a dictionary from the client. Teams that have invested in prompt injection guardrails for AI agents sometimes have zero coverage on the persistence layer beneath them, and an attacker with a choice will take the SQL injection every time.
Three practical adjustments follow.
Treat the checkpoint store as a trust boundary, not an implementation detail. Anything that can write to it can, in the worst case, execute in your runtime. That deserves the same review as a message queue an untrusted producer can publish to.
Make filter construction server-side by contract. The agent server should build filter dictionaries from a validated session, never accept one from a request body. This single rule would have neutralised two of the three CVEs regardless of version.
Pin and monitor the framework, not just the model. Model versions get change-managed carefully while langgraph floats on a caret range. The same discipline that applies to MCP server hardening applies here: agent-adjacent infrastructure needs a named owner and a patch SLA.
India-specific considerations
For Indian teams, the compliance exposure is concrete rather than theoretical. Agent checkpoint state routinely contains names, contact details, order histories and support transcripts, all of which are personal data under the Digital Personal Data Protection Act 2023. The Act's substantive obligations tighten through 2026 ahead of hard enforcement in May 2027, and the Data Protection Board of India can impose penalties reaching ₹250 crore, roughly $26 million, for major violations.
Two consequences follow for anyone running a self-hosted agent on Indian customer data. First, a checkpoint-table leak through CVE-2025-67644 is a personal-data breach, not just a bug, and your breach-notification clock is a legal one. Second, retention limits apply to checkpoints. Most teams never set a TTL on the checkpoint table, so a graph that ran once in March is still holding a full conversation transcript in August. Set retention, and document it, alongside the rest of the work in the DPDP Act engineering playbook.
The practical sequencing for an Indian engineering team is patch, then scope, then retain. Get to the fixed versions this week. Then determine whether any user-controlled string ever reached a filter key, because that answer decides whether you are writing a changelog entry or a breach assessment. Then put a retention policy on the store so the next incident has a smaller blast radius. For the wider picture of what production agents need before they touch customer data, see our guide to enterprise AI agents in production.
FAQ
How eCorpIT can help
eCorpIT builds and hardens production AI agent systems for teams in India and abroad, and this is exactly the kind of work our senior engineering teams do: inventory the framework and checkpointer versions across every environment, trace which request paths reach a filter key, turn on strict deserialisation without breaking your graphs, and put retention and least-privilege controls on the state store. We are ISO 27001:2022 certified and CMMI Level 5 appraised, and we design applications aligned with DPDP requirements. If you are running self-hosted LangGraph and want a second pair of eyes on the persistence layer before your next audit, contact us and we will scope a review.
References
- LangGraph Flaw Chain Exposes Self-Hosted AI Agents to Remote Code Execution - The Hacker News, 12 June 2026
- CVE-2026-28277: LangGraph checkpoint loading has unsafe msgpack deserialization (GHSA-g48c-2wqr-h844) - GitHub Advisory Database, 5 March 2026
- GHSA-9rwj-6rc7-p77c: LangGraph SQLite checkpointer SQL injection - langchain-ai/langgraph security advisories
- GHSA-5mx2-w598-339m: RediSearch query injection in @langchain/langgraph-checkpoint-redis - langchain-ai/langgraphjs security advisories
- CVE-2025-67644 advisory for langgraph-checkpoint-sqlite - GitLab Advisory Database
- From SQLi to RCE: exploiting LangGraph's checkpointer - Check Point Research, 2026
- CVE-2026-27022: LangGraph Redis checkpoint query injection - SentinelOne Vulnerability Database, 27 February 2026
- Pull request 1943: escape RediSearch tag values in the Redis checkpointer - langchain-ai/langgraphjs
- NVD entry for CVE-2026-28277 - National Vulnerability Database
- AI used to help plan the break-in, now it's doing the break-in - Help Net Security, 15 July 2026
- AI adoption creates critical cloud security gaps for enterprises - Check Point Software press release, 2026
- India's DPDP timeline: critical compliance deadlines for 2026-27 - India Briefing, 11 May 2026
- Check Point's 2026 Cloud Security Report: Securing the AI Transformation - Unite.AI summary of the Check Point and Cybersecurity Insiders survey, 26 May 2026
Last updated: 5 August 2026.