| Package | Affected versions | Patched versions |
|---|---|---|
| langgraph-checkpoint | < 4.0.0 | 4.0.0 |
A Remote Code Execution vulnerability exists in LangGraph's caching layer when applications enable cache backends that inherit from BaseCache and opt nodes into caching via CachePolicy. Prior to langgraph-checkpoint 4.0.0, BaseCache defaults to JsonPlusSerializer(pickle_fallback=True). When msgpack serialization fails, cached values can be deserialized via pickle.loads(...).
Caching is not enabled by default. Applications are affected only when:
cache=... to StateGraph.compile(...) or otherwise configuring a BaseCache implementation)CachePolicyExample (enabling a cache backend and opting a node into caching):
from langgraph.cache.memory import InMemoryCache
from langgraph.graph import StateGraph
from langgraph.types import CachePolicy
def my_node(state: dict) -> dict:
return {"value": state.get("value", 0) + 1}
builder = StateGraph(dict)
builder.add_node("my_node", my_node, cache_policy=CachePolicy(ttl=120))
builder.set_entry_point("my_node")
graph = builder.compile(cache=InMemoryCache())
result = graph.invoke({"value": 1})
With pickle_fallback=True, when msgpack serialization fails, JsonPlusSerializer can fall back to storing values as a tuple and later deserialize them via . If an attacker can place a malicious pickle payload into the cache backend such that the LangGraph process reads and deserializes it, this can lead to arbitrary code execution.
("pickle", <bytes>)pickle.loads(...)Exploitation requires attacker write access to the cache backend. The serializer is not exposed as a network-facing API.
This is fixed in langgraph-checkpoint>=4.0.0 by disabling pickle fallback by default (pickle_fallback=False).
Arbitrary code execution in the LangGraph process when attacker-controlled cache entries are deserialized.
BaseCache default serializer configuration inherited by cache implementations (InMemoryCache, RedisCache, SqliteCache):
libs/checkpoint/langgraph/cache/base/__init__.py (pre-fix default: JsonPlusSerializer(pickle_fallback=True))JsonPlusSerializer deserialization sink:
libs/checkpoint/langgraph/checkpoint/serde/jsonplus.pyloads_typed(...) calls pickle.loads(data_) when type_ == "pickle" and pickle fallback is enabledAn attacker must be able to write attacker-controlled bytes into the cache backend such that the LangGraph process later reads and deserializes them.
This typically requires write access to a networked cache (for example a network-accessible Redis instance with weak/no auth or shared cache infrastructure reachable by other tenants/services) or write access to local cache storage (for example a writable SQLite cache file via permissive file permissions or a shared writable volume).
Because exploitation requires write access to the cache storage layer, this is a post-compromise / post-access escalation vector.
langgraph-checkpoint>=4.0.0.Running one of these products? Scan your site to see whether it exposes a vulnerable version.
Scan my site free