Skip to content

fix: cross-check intent_hash in agent manifest binding verification - #578

Merged
imran-siddique merged 1 commit into
agentrust-io:mainfrom
yongikim:fix/intent-hash-binding-check
Aug 26, 2026
Merged

fix: cross-check intent_hash in agent manifest binding verification#578
imran-siddique merged 1 commit into
agentrust-io:mainfrom
yongikim:fix/intent-hash-binding-check

Conversation

@yongikim

@yongikim yongikim commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

What

Add intent_hash to the field set that Step 5 (verify_trace_claim) cross-checks against the Agent Manifest binding, and add a regression test covering the mismatch case.

Why

Closes #577. expected_identity in src/cmcp_verify/verify.py compares 8 fields between the Claim's gateway.agent_identity and the recomputed AgentManifestBinding, but omits intent_hash, even though verify_agent_manifest_binding() already computes it correctly on binding.intent_hash. A Claim can currently assert a fabricated intent_hash and still pass agent_manifest.binding verification.

Security impact

Low current exploitability: the intent field is not yet read by any policy or tool-catalog enforcement path, so this does not bypass an active control. But it removes the only mechanical check on an agent's declared purpose (Agent Manifest spec §3.9), and the spec itself (§3.9.1) notes there is no semantic backstop for this anywhere else in the ecosystem. Does not touch src/cmcp_gateway/audit/, src/cmcp_gateway/tee/, or src/cmcp_gateway/policy/.

Test plan

  • pytest tests/unit/ -v passes (adds test_agent_manifest_binding_intent_hash_mismatch_fails to tests/unit/test_verify.py, mirroring the existing test_agent_manifest_binding_mismatch_fails)
  • ruff check src/cmcp_verify/verify.py tests/unit/test_verify.py passes
  • mypy src/cmcp_verify/verify.py passes
  • bandit -r src/ -c pyproject.toml passes
  • Manual test performed (describe steps below if applicable)

DCO sign-off

Signed-off-by: yongikim <yongi.kim08@gmail.com>
@yongikim
yongikim requested review from a team as code owners August 26, 2026 00:23

@imran-siddique imran-siddique left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving to release the hold gate. Three workflows were sitting in action_required, so cmcp's CI had not run on this at all: two checks reported where this repo normally runs twelve. Releasing them now and I will report before merging.

Verified the defect at main rather than taking the description. expected_identity at verify.py:857 holds eight fields and omits intent_hash, while binding.intent_hash is computed at agent_manifest.py:379 through agent_manifest_sdk.intent_hash(manifest). So the value is derived correctly and then dropped on the floor at the comparison. A claim can assert a fabricated intent_hash and pass binding verification, exactly as you say.

This is the same defect class as cmcp#557 last week, where the chained TPM verifier parsed the signature scheme and digest and then passed only the bare signature. Computed, reported, not enforced. Reported-but-unenforced is worse than absent, because a field appearing in a verification result reads as checked to anyone downstream, and nobody re-derives it.

I also checked the None path, since intent_hash is typed str | None and an issuer may declare no intent. Both sides None compares equal and passes; a claim asserting an intent_hash against a manifest that declares none mismatches and fails. Fail-closed in the direction that matters, so the one-line addition needs no guard around it. Worth stating because a reviewer glancing at a nullable field in an equality check would reasonably ask.

Your security framing is the right level of claim and I want to credit it. "Low current exploitability: the intent field is not yet read by any policy or tool-catalog enforcement path, so this does not bypass an active control" is the sentence most reports would have left out, because it makes the finding sound smaller. It also happens to be the sentence that makes the rest of the report trustworthy. Naming what it does cost, the only mechanical check on an agent's declared purpose with no semantic backstop elsewhere, is the argument that actually carries it.

Filing #577 first and then the PR, rather than opening the PR alone, also means the defect is recorded independently of whether this particular fix is the one that lands.

CI report to follow.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@imran-siddique

Copy link
Copy Markdown
Member

CI report, as promised. Releasing the three held workflows took this from two checks to thirteen, all green: tests on 3.11, 3.12 and 3.13 across ubuntu and windows, CodeQL, governance and the Docker build. gate is our maintainer hold rather than a result.

Merging. Thanks for filing #577 alongside it.

@imran-siddique
imran-siddique merged commit 21df5b4 into agentrust-io:main Aug 26, 2026
12 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Agent Manifest binding does not cross-check intent_hash required by Agent Manifest spec §3.9

3 participants