Request binding catches argument mutation

Authorization is not the last integrity check. GuardLLM binds a proposed tool and its arguments to the current message, then rejects execution if the arguments change.

You are here
SourceIntegritySink

Path 1: arguments mutate

1. Record the proposal

STATE RECORDED
{"query": "quarterly plan"}
Canonical argument hash stored in the binding.

2. Verify immediately before execution

BLOCKED
The execution payload carries an unapproved extra field, so the recomputed canonical hash no longer matches: {"query": "quarterly plan", "scope": "all"}
Args hash mismatch (arguments changed since proposal)

Path 2: binding expires

1. Record a second proposal

STATE RECORDED
A second binding preserves the approved arguments and carries a one-second TTL.
Canonical argument hash stored in the binding.

2. Verify after the TTL

BLOCKED
The arguments are unchanged this time. Only the clock moved.
Binding expired (TTL exceeded)

One verifier, two artifacts: both paths are checked by the same SecurityPipeline. What differs is the binding each path produced, which is why the fixture records the artifact per step rather than the object.

Evidence, scope, and reproduction
Adversary A2/A3IntegrityT-IN6 · T-IN7A-AS5 · A-AS6Source: SecurityPipeline.check_tool_executionTest: tests/test_demo_scenarios.py

Exact fixture test: tests/test_demo_scenarios.py::test_request_binding_fixture

.venv/bin/python -m pytest tests/test_demo_scenarios.py::test_request_binding_fixture -q

Generated fixture