Repository navigation
fix(intent_bridge): validate JWK and kid before signature verification and require dict authorization in sign_bridge (#507) - #510
Merged
imran-siddique merged 1 commit intoOct 14, 2026
Conversation
…n and require dict authorization in sign_bridge (agentrust-io#507) Signed-off-by: Raghuvar Durga <177662415+drk-ram@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
imran-siddique
approved these changes
Oct 14, 2026
imran-siddique
left a comment
Member
There was a problem hiding this comment.
Verified locally. 8 of the new tests fail against main's intent_bridge.py; all 84 pass on this head. Nothing that was rejected now passes: the change is that a key-id mismatch or an unusable JWK reports as itself instead of as an invalid signature.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Closes #507.
verify_bridge(src/agentrust_trace/intent_bridge.py):isinstance(trusted_authorizer_jwk, dict)and raiseIntentBridgeError("trusted_authorizer_jwk must be an object")before readingkidor reconstructing the public key, matchingverify_successor_artifact.trusted_authorizer_jwk.get("kid") == authorization["authorizer_key_id"]before reconstructing the key and verifying the Ed25519 signature, matchingverify_successor_artifact, so an authorization naming a differentauthorizer_key_idreports"authorizer_key_id does not identify the trusted key"rather than failing insidepub.verify(signature, body)as"authorization signature is invalid"._pubkey_from_jwk(trusted_authorizer_jwk)out of thetry ... except Exception: raise IntentBridgeError("authorization signature is invalid")block and wrap itsValueErrorinIntentBridgeError(f"trusted_authorizer_jwk is unusable: {exc}"), matching howverify_bridgewrapssign._b64url_decodeandsign._integer_valueso a malformed caller JWK is not misreported as an invalid signature and does not escape as a bareValueError.verify_successor_artifact(src/agentrust_trace/intent_bridge.py):_pubkey_from_jwk(trusted_observer_jwk)out of thetry ... except Exception: raise IntentBridgeError("successor signature is invalid")block and wrap itsValueErrorinIntentBridgeError(f"trusted_observer_jwk is unusable: {exc}").sign_bridge(src/agentrust_trace/intent_bridge.py):isinstance(authorization, dict)and raiseIntentBridgeError(f"authorization must be a JSON object, got {type(authorization).__name__}"), matchingsign.sign_record,provenance.sign_record, andintent_bridge.digest_jcs. Innerauthorizationfield validation stays inverify_bridgebecauseverify_bridgechecksdecision != "allow", timestamps,scope,pic, digests, andtranscript_requiredafterpub.verify(signature, body), and the test suite usessign_bridgeto sign intentionally malformedauthorizationdicts that exercise those verifier checks.Independent cold-reader review (
CONTRIBUTING.md"Before a pull request is reviewed")An independent cold-reader review of
git diff main..HEADand the draft PR description found:test_bridge_naming_another_authorizer_key_id_is_rejectedhad no control assertion showing that an untrusted key with the matchingkid="key-7"still reachespub.verifyand raises"authorization signature is invalid", and did not test the signing key itself with a mismatched or missingkid. Added that control and the same-key mismatched/missingkidcases, and aligned the test docstring with_fixture()'sauthorizer_key_id="key-7".provenance.verify_recordwraps_pubkey_from_jwk(provenance.verify_recordactually wrapsjwk_thumbprint). Updated the description to citeverify_bridge's wrapping ofsign._b64url_decodeandsign._integer_valueinstead, and explained whysign_bridgevalidatesisinstance(authorization, dict)without validating inner fields.Type of change
Reference-library bug fix in
src/agentrust_trace/intent_bridge.py. No normative spec text or schema changes.Spec section
None.
docs/integration/pic-trace-bridge-v1.md(informative).Tests for a fix
Each change in
src/agentrust_trace/intent_bridge.pyhas a corresponding test intests/test_intent_bridge.pythat fails onmain(21 fail on behaviour, 0 fail on a missing name or fileundertools/review_bar.py --base main --head HEAD) and when that specific change is switched off:verify_bridgeisinstance(trusted_authorizer_jwk, dict)check:tests/test_intent_bridge.py::test_verify_bridge_rejects_non_object_trusted_authorizer_jwkfails when switched off.verify_bridgetrusted_kidcheck before_pubkey_from_jwk/pub.verify:tests/test_intent_bridge.py::test_bridge_naming_another_authorizer_key_id_is_rejectedfails when the check is moved back afterpub.verify(raising"authorization signature is invalid"first on a different key) or when removed (DID NOT RAISE IntentBridgeErroron the same key with a different or missingkid).verify_bridge_pubkey_from_jwk(trusted_authorizer_jwk)hoisted and wrapped as"trusted_authorizer_jwk is unusable":tests/test_intent_bridge.py::test_verify_bridge_reports_unusable_trusted_authorizer_jwk_instead_of_invalid_signaturefails when_pubkey_from_jwkis left insidetry: pub.verify(...)(raising"authorization signature is invalid"instead) or left unwrapped (raising a bareValueError).verify_successor_artifact_pubkey_from_jwk(trusted_observer_jwk)hoisted and wrapped as"trusted_observer_jwk is unusable":tests/test_intent_bridge.py::test_verify_successor_artifact_reports_unusable_trusted_observer_jwkfails when_pubkey_from_jwkis left insidetry: pub.verify(...)(raising"successor signature is invalid"instead) or left unwrapped (raising a bareValueError).sign_bridgeisinstance(authorization, dict)check:tests/test_intent_bridge.py::test_sign_bridge_requires_authorization_to_be_a_json_objectfails withDID NOT RAISE IntentBridgeErrorwhen theisinstance(authorization, dict)guard is switched off.Checklist
git commit -s)CHANGELOG.mdupdated (for any normative change)<!-- CHANGED: #NNN: description -->in spec textContributor: Raghuvar Durga (@drk-ram)
Fixes: #508