| D1 |
SQL injection via filter keys in PostgreSQL store |
Traced filter key handling through
libs/checkpoint-postgres/langgraph/store/postgres/base.py:_get_filter_condition.
All filter operations use parameterized queries with %s
placeholders. Keys map to json_extract path operators with
type-safe wrappers. |
libs/checkpoint-postgres/langgraph/store/postgres/base.py:_get_filter_condition
— parameterized %s for all value bindings; key names used
in value->%s path expressions are also
parameterized |
Disproven: All SQL operations in PostgreSQL store are fully
parameterized. No injection vector. |
| D2 |
SQL injection via filter keys in SQLite store (post-fix) |
Traced current filter handling through
libs/checkpoint-sqlite/langgraph/store/sqlite/base.py and
libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/utils.py:_validate_filter_key.
Regex ^[a-zA-Z0-9_.-]+$ applied to all filter keys before
use in json_extract() expressions. |
libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/utils.py:_validate_filter_key
— regex validation blocks injection characters. Published advisories
GHSA-9rwj-6rc7-p77c and GHSA-7p73-8jqx-23r8 confirmed fixed. |
Disproven: SQL injection in SQLite store filter keys is remediated
by regex validation. |
| D3 |
Command injection via CLI subprocess execution |
Traced CLI subprocess invocation path.
libs/cli/langgraph_cli/exec.py:subp_exec uses
asyncio.create_subprocess_exec with list-based arguments
(not shell=True).
has_disallowed_build_command_content blocks shell
metacharacters in user-provided Dockerfile lines. |
libs/cli/langgraph_cli/exec.py:subp_exec — explicit
exec-style invocation;
libs/cli/langgraph_cli/config.py:has_disallowed_build_command_content
— regex blocks \|, ;, $,
>, <, backtick, \, single
& |
Disproven: CLI uses exec-style subprocess and validates build
command content. No shell injection vector. |
| D4 |
Tool argument injection via InjectedState/InjectedStore
dict-splatting |
Investigated whether LLM-generated tool call arguments could
override system-injected values (InjectedState, InjectedStore,
ToolRuntime) via key collision in the dict merge at
libs/prebuilt/langgraph/prebuilt/tool_node.py:ToolNode._inject_tool_args
line 1380. Traced four independent defense layers. |
(1) tool_call_schema at langchain-core
base.py filters injected params from LLM schema. (2)
{**llm_args, **injected_args} merge puts system values last
— system wins on collision. (3) Pydantic model_validate
with extra="ignore" drops unknown keys. (4) Output
construction at base.py only includes declared model
fields. |
Disproven: Four-layer defense prevents LLM arguments from overriding
system-injected values. Merge order guarantees system values win. No
adversarial collision path exists. |