fix(signing): register vector 027 + skip in verifier conformance#682
Merged
Conversation
Upstream compliance cache added vector 027-webhook-registration-authentication-unsigned, which tests the webhook-security downgrade rule: a webhook registration whose body carries push_notification_config.authentication MUST require RFC 9421 signing even when the operation is not in the verifier's required_for list. The fixture ships the adversarial shape verbatim (unsigned bearer request with authentication in the body), so the builder just needs a passthrough mutation. The verifier does not yet inspect request bodies for this rule, so vector 027 joins 021-026 on the unimplemented-verifier skip lists; the conformance suite skips it, the grader e2e/mcp tests skip it, and count assertions move from 26 to 27 negatives. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…us export Upstream schema bundle regenerated ListCreativesRequest, CheckGovernanceResponse, and related types as open-indexed intersection types; CatalogAction and CatalogItemStatus moved from tools.generated to core.generated. Regen is mechanical; index.ts re-exports move to match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
4 tasks
bokelley
added a commit
that referenced
this pull request
Apr 21, 2026
…1-027 (#687) * feat(signing): implement verifier conformance for negative vectors 021-027 Closes #683. The RFC 9421 reference verifier now enforces the full #verifier-checklist-requests + #webhook-security profile against the seven negative conformance vectors that had been skipped since #631. Vectors 021-026 were already implemented library-side (duplicate Signature-Input labels, multi-valued content-type / content-digest, unquoted string params, JWK alg/crv consistency, non-ASCII @authority); the conformance suite was skipping them via `NEGATIVE_VECTORS_UNIMPLEMENTED`. Removing that skip-list surfaced one harness bug: the test runner's eager `canonicalTargetUri(vector.request.url)` threw on vector 026's U-label authority before the verifier's own parse-time check could fire. Deferred the precompute until a `replay_cache_entries` preload actually needs it. Vector 027 (webhook-authentication downgrade resistance) required new verifier logic and builder registration: - `verifyRequestSignature` on the unsigned branch now rejects any request whose JSON body carries a non-empty `push_notification_config.authentication` anywhere in the tree — inside nested arrays, under any parent key, and regardless of `Content-Type`. Closes the captured-bearer-token -> hostile webhook callback redirect path; `required_for` precedence is preserved so an operation already on the always-sign list still gets the more specific error message. - DoS hardened: body size capped at 1 MB (oversized unsigned bodies fail closed with `request_signature_required` since we can't prove absence of webhook auth within the pre-crypto budget), traversal capped at depth 64 so pathologically nested JSON can't blow the stack. - Builder registers 027 as a passthrough mutator since the adversarial shape lives in the fixture body, not a programmatic mutation. Test coverage: nine new unit tests in `request-signing-verifier-api.test.js` lock the surface around the conformance vector — present-without-auth, empty auth, null auth, string-typed auth, array-nested auth, non-JSON body, oversized body, and signed requests carrying auth material (must reach the crypto path, not re-reject at step 0). Grader e2e + MCP tests drop the upstream-added `UNIMPLEMENTED_VERIFIER_RULE_VECTORS` skip introduced in #682; full suite 4502 pass / 0 fail / 6 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: prettier on new webhook-auth verifier tests Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: trigger CI on formatting-fixed head --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Upstream compliance cache (
compliance/cache/latest/test-vectors/request-signing/negative/) added vector027-webhook-registration-authentication-unsigned, breaking CI on any open PR. Vector 027 tests the #webhook-security downgrade resistance rule: a webhook registration whose body carriespush_notification_config.authenticationMUST require RFC 9421 signing even when the operation is absent from the verifier'srequired_forlist.The fixture ships its adversarial shape verbatim (unsigned bearer request with
authenticationin the body), so the builder only needs a passthrough mutation — no programmatic mutation required. The verifier does not yet inspect request bodies for this rule, so vector 027 is added to the unimplemented-verifier skip lists alongside 021–026.Changes
src/lib/testing/storyboard/request-signing/builder.ts— passthrough mutation for027-webhook-registration-authentication-unsigned.test/request-signing-vectors.test.js— add027-webhook-registration-authentication-unsigned.jsontoNEGATIVE_VECTORS_UNIMPLEMENTED(skips the conformance check until the verifier learns the rule).test/request-signing-grader-e2e.test.js+test/request-signing-grader-mcp.test.js— add aUNIMPLEMENTED_VERIFIER_RULE_VECTORSconstant and fold it intoSKIPPED_VECTORS(alongsideCAPABILITY_PROFILE_VECTORS). Count assertions move 26 → 27.test/request-signing-grader-vectors.test.js+test/request-signing-runner-integration.test.js— count assertions move 26 → 27 (and 25 → 26 for the skipVectors subtest).Scope
CI-unblocking patch only. Implementing the body-inspection rule in the verifier is a separate follow-up; once that lands, vector 027 moves off the skip lists.
Test plan
node --test test/request-signing-*.test.js— 54/54 pass locallynpm test— 4476 pass / 0 fail / 13 skipped (27's conformance + the existing 6 from 021–026)tsc --noEmit— clean (pre-push hook)🤖 Generated with Claude Code