Skip to content

fix(verify/tdx,embodied_action): enforce hex format in verify_tdx_measurement and guard non-dict inputs in verify_embodied_action_evidence (#803) - #806

Open
drk-ram wants to merge 1 commit into
agentrust-io:mainfrom
drk-ram:drk-ram-fix-tdx-embodied-803
Open

drk-ram wants to merge 1 commit into
agentrust-io:mainfrom
drk-ram:drk-ram-fix-tdx-embodied-803

Conversation

@drk-ram

@drk-ram drk-ram commented Oct 23, 2026

Copy link
Copy Markdown

What

Enforce ^sha384:[0-9a-f]{96}$ measurement format and valid hex report_data_hex in verify_tdx_measurement, and guard non-dict inputs and exact digest lengths in verify_embodied_action_evidence.

Why

Closes #803.

Security impact

Ensures malformed TDX measurement strings or report_data_hex values are classified accurately (invalid_measurement_format and report_data_mismatch), and prevents unhandled AttributeError / TypeError when verify_embodied_action_evidence receives non-dict inputs or malformed claim_json structures.

Test plan

  • pytest passes (pytest tests/unit/test_tdx_verify.py tests/unit/test_embodied_action_evidence.py -q)
  • ruff check passes (ruff check src/cmcp_verify/tdx.py src/cmcp_verify/embodied_action.py tests/unit/test_tdx_verify.py tests/unit/test_embodied_action_evidence.py)
  • mypy passes (mypy src/cmcp_verify/tdx.py src/cmcp_verify/embodied_action.py)
  • Manual test performed

DCO sign-off

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

🟡 Contributor Check: MEDIUM

Check Result
Profile MEDIUM
Credential LOW
Overall MEDIUM

Automated check by AgenTrust Contributor Check.

@github-actions github-actions Bot added the needs-review:MEDIUM Contributor check flagged MEDIUM risk label Oct 23, 2026
@drk-ram
drk-ram force-pushed the drk-ram-fix-tdx-embodied-803 branch 2 times, most recently from 5f35696 to 6513313 Compare October 23, 2026 15:33
carloshvp
carloshvp previously approved these changes Oct 24, 2026

@carloshvp carloshvp 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.

Reviewed exact head 65133135cee9c487036649a2997ca95c53fd81c2 in an isolated checkout.

The measurement parser now requires the declared lowercase SHA-384 format, malformed report data follows the controlled mismatch path, and embodied-action evidence rejects malformed containers and digest values without treating receipt validity as proof of policy authorization or physical completion. No blocking finding in the changed paths.

Local hash-locked Python 3.12.10 validation: 2,528 unit tests passed, 20 skipped; pip check, Ruff, mypy and Bandit passed. All PR commits have sign-offs. git diff --check notes one extra blank line at test_tdx_verify.py EOF, a nonblocking cleanup. Hosted CI and required maintainer gates still need completion.

Reviewed with OpenAI Codex.

@noah-ing noah-ing left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed current head 65133135cee9c487036649a2997ca95c53fd81c2. The new shape guards treat a supplied but malformed TRACE Claim like no Claim at all. With the repository’s valid signed ROS2 evidence fixture, claim_json={"trace": None, "gateway": None} returns verified=True, no failures or warnings, and omits all policy, catalog, and agent cross-bindings. The added test currently asserts that success. Please preserve None as the explicit no-Claim mode, but return a nonverified result when a supplied Claim has malformed sections, and add a negative regression for that distinction. This is a fail-closed helper-contract concern; I have not shown a bypass of the documented flow that verifies the full TRACE Claim first.

The TDX format changes behaved as intended. Local exact-head validation: 2,528 unit tests passed, 20 skipped; focused negative fixture replay passed. Hosted CI is blocked by the existing locked-dependency audit, and required governance checks remain outstanding.

@drk-ram

drk-ram commented Oct 24, 2026

Copy link
Copy Markdown
Author

Thanks @noah-ing and @carloshvp! Updated verify_embodied_action_evidence in src/cmcp_verify/embodied_action.py so claim_json=None remains the explicit no-Claim mode while any supplied claim_json with non-object claim_json, missing/malformed trace.policy.bundle_hash, or missing/malformed gateway.catalog.hash records a failure and returns verified=False (covered in tests/unit/test_embodied_action_evidence.py), and trimmed the EOF blank line in tests/unit/test_tdx_verify.py.

@noah-ing

Copy link
Copy Markdown
Collaborator

Thanks for the follow-up. I checked head 944c03c6700410f1382d843e2c71162259834913 with the repository’s signed ROS2 external-evidence fixture. The malformed supplied trace/policy/catalog cases now fail, while claim_json=None remains the explicit no-Claim mode. One supplied malformed section still silently drops a binding: with valid policy and catalog context, set gateway.agent_identity to null, {}, or {"agent_id": 42}. The helper returns verified=True with no failure and omits the agent_id comparison; the existing non-object-identity test expects that result. The profile calls for comparing identity when it is present. Please distinguish absent identity from malformed-present identity, return nonverified for the latter, and add a negative regression. This remains a scoped helper-contract concern: I have not demonstrated a bypass of the full schema-validated Claim flow. The focused 41-test suite passed.

@dinakarjs dinakarjs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I prepared a signed adoption companion addressing the outstanding review finding: dinakarjs#6

Validation: unit suite 2547 passed/6 skipped; conformance+integration+confinement 114 passed/23 skipped. Ruff on src/tests, strict mypy and Bandit passed. All five malformed-identity parameter cases fail by assertion when just this fix is removed; valid/absent controls pass with the repair.

Please cherry-pick/adopt the companion and request independent re-review of the resulting head. I have contributed the follow-up and am not approving my own contribution.

@drk-ram

drk-ram commented Oct 24, 2026

Copy link
Copy Markdown
Author

Thanks @noah-ing! Distinguished absent gateway.agent_identity ("agent_identity" not in gateway, which skips the agent_id cross-check) from a present-but-malformed gateway.agent_identity (None, "not-an-object", {}, {"agent_id": 42}, {"agent_id": ""}), which now records a failure and returns verified=False, covered by regression assertions in tests/unit/test_embodied_action_evidence.py.

@drk-ram

drk-ram commented Oct 25, 2026

Copy link
Copy Markdown
Author

Thanks @dinakarjs and @noah-ing! Adopted @dinakarjs's signed companion commit 2411f8f (fix/review-806-20261025) directly as the branch head with authorship and signature preserved.

@drk-ram
drk-ram force-pushed the drk-ram-fix-tdx-embodied-803 branch from a59495d to 2411f8f Compare October 25, 2026 04:48

@noah-ing noah-ing left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed exact head 2411f8f33811a9afdd63cfe80968527330d8c483. The supplied-but-malformed gateway.agent_identity cases now fail explicitly, while an absent identity remains optional; valid and mismatched identities behave as expected. I replayed nine cases against the signed ROS2 evidence fixture with receipt checking enabled. The focused tests passed (64/64), as did the full unit suite (2,533 passed, 20 skipped), Ruff, mypy, dependency and whitespace checks. This resolves my requested change, so I approve this scoped verifier fix. The normal hosted checks and merge gates still need to complete.

carloshvp
carloshvp previously approved these changes Oct 25, 2026

@carloshvp carloshvp 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.

Reviewed exact head 2411f8f33811a9afdd63cfe80968527330d8c483 in an isolated checkout.

The updated source additionally rejects a supplied malformed Claim context and malformed present agent identity, while keeping the explicit no-Claim receipt-only mode and optional absent identity. The measurement, digest and container guards remain intact. Current receipt/Claim binding tests pass with valid controls; the reported receipt facts remain distinct from authorization and physical completion. No blocking finding in the updated paths.

Independent validation in a fresh repository-hash-locked Python 3.12.10 environment: 2,533 tests passed, 20 skipped; pip check, configured Ruff, mypy, Bandit and diff whitespace checks passed. Commit sign-offs are present. Hosted CI and applicable independent maintainer/security gates remain separate prerequisites to merge.

Reviewed with OpenAI Codex.

@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

❌ Patch coverage is 94.64286% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/cmcp_verify/embodied_action.py 93.47% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@rajnisht7 rajnisht7 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.

overall changes looks good, one gap still needs hardening:

current checks correctly reject non-string / empty / odd-length / non-hex. After that we still do:

expected_rd = bytes.fromhex(report_data_hex[:REPORT_DATA_SIZE * 2])

so any pure-hex string longer than 128 chars is accepted as long as the first 128 match the actual 64-byte REPORT_DATA. The suffix is silently dropped and verification can still pass. reproduced it too with 130 / 168 / much longer inputs

short values are intentionally supported (zero-padded), so the missing piece is an upper bound:

len(report_data_hex) > REPORT_DATA_SIZE * 2

->treat as report_data_mismatch.kindly add that check and a small regression (valid 128 hex + extra "aa" → fail, not verify). The quote path has the same [:128] pattern.

@noah-ing noah-ing left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Updating my earlier approval in light of @rajnisht7's new finding at current head c2920f4ae450876923a15df513a5d491e3eed93c. I independently reproduced it: the direct TDX helper accepts a matching 128-character report_data_hex with additional hex bytes appended, records report_data as verified, and silently ignores the suffix. The quote path also truncates the supplied value. I did not establish a bypass of the full Claim path, which supplies a canonical 64-byte value.

Please reject inputs longer than 128 hex characters before decoding, retain the intended support for shorter zero-padded values, and add a negative regression for a valid value plus aa in the direct and quote paths. This is a scoped change request on the input-length contract; my earlier approval should not be read as covering this newly established gap.

…rt_data bound in TDX verifiers and fail closed on malformed embodied-action inputs (agentrust-io#803)

- Require lowercase sha384:<96 hex chars> format and <=128 hex characters for report_data in verify_tdx_measurement and verify_tdx_quote before decoding, preserving zero-padding for shorter values.
- Fail closed when supplied claim_json or gateway.agent_identity is malformed in verify_embodied_action_evidence while keeping claim_json=None as explicit receipt-only mode.
- Add negative regression tests for oversized 130-char report_data_hex in both direct and quote TDX paths and malformed embodied-action claim sections.

Signed-off-by: Raghuvar Karthik Durga <177662415+drk-ram@users.noreply.github.com>
@drk-ram

drk-ram commented Oct 31, 2026

Copy link
Copy Markdown
Author

Thank you @rajnisht7 and @noah-ing! Rebased onto origin/main (1fbc1b2) and addressed in d897245:

  • Added len(report_data_hex) > REPORT_DATA_SIZE * 2 (128) bounds checks in both verify_tdx_measurement and verify_tdx_quote (src/cmcp_verify/tdx.py) so inputs longer than 128 hex characters fail closed as report_data_mismatch before hex decoding while preserving zero-padding for shorter values.
  • Added negative regression tests in tests/unit/test_tdx_verify.py and tests/unit/test_tdx_quote_verify.py verifying that a valid 128-character report_data_hex plus "aa" (130 chars) is rejected in both the direct and quote paths with verified is False, failure_reason == "report_data_mismatch", and "report_data" not in verified_fields.

@noah-ing noah-ing left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed exact head d897245d57139b9db7cd09e83357a73d37cef08f. Both the direct TDX measurement helper and quote verifier now reject report_data_hex longer than 128 characters before decoding, while retaining the intended shorter zero-padded inputs. The committed valid-value-plus-aa regressions require a failed result and no verified report_data field.

In a fresh Python 3.12.14 environment installed from the repository's hash-locked development requirements, the focused TDX direct, quote and embodied-action selection passed (75 passed, 2 skipped). Ruff passed on the touched TDX source and tests. This resolves my earlier overlong-input changes request, so I approve this scoped repair on this head. The result does not establish a full-Claim bypass or hardware validation; substantive hosted checks and the maintainer gate still need their normal disposition.

@carloshvp carloshvp 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.

Reviewed commit d897245d57139b9db7cd09e83357a73d37cef08f.

TDX measurement and nonce formats are checked before use. Embodied-action verification refuses non-object inputs and a supplied claim with missing or malformed required policy/catalog bindings; the digest lengths now match the selected hash algorithm.

Focused tests: 75 passed, 2 skipped; repository Ruff, mypy and configured Bandit pass. This is software verifier/parser evidence. Required hosted checks and the independent security review requirement remain in force.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-review:MEDIUM Contributor check flagged MEDIUM risk

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(verify/tdx,embodied_action): enforce hex format in verify_tdx_measurement and guard non-dict inputs in verify_embodied_action_evidence

6 participants