Skip to content

fix(webauthn): escape clientDataJSON strings per CCDToString#196

Open
AlfioEmanueleFresta wants to merge 1 commit into
masterfrom
fix/webauthn-clientdata-escaping
Open

fix(webauthn): escape clientDataJSON strings per CCDToString#196
AlfioEmanueleFresta wants to merge 1 commit into
masterfrom
fix/webauthn-clientdata-escaping

Conversation

@AlfioEmanueleFresta
Copy link
Copy Markdown
Member

WebAuthn L3 §5.8.1.2 specifies that clientDataJSON strings must be escaped via CCDToString (a strict subset of ECMA-262 / RFC 8259 string-escape rules). ClientData::to_json currently hand-rolls a JSON object via format!(), concatenating the origin and topOrigin strings unescaped, which produces malformed or attacker-injectable JSON when those strings contain ", \, or U+0000-U+001F.

Empirical repro on the base branch: setting origin to https://example.com","origin":"https://attacker.com yields a document with two origin keys.

Stacked on top of #190 (which is stacked on #188 / #186). The RequestOrigin plumbing introduced by #188 already correctly populates ClientData::origin and ClientData::top_origin from the URL origin; that work is preserved unchanged here.

Changes

  • Replace hand-rolled format!() in ClientData::to_json with a #[derive(Serialize)] wire struct that mirrors the spec field order (type, challenge, origin, topOrigin?, crossOrigin). serde_json's RFC 8259 string encoder is a strict superset of CCDToString.
  • topOrigin is omitted from the output entirely when absent (via skip_serializing_if), preserving the existing behaviour.
  • Regression tests for: origin containing ", origin containing \, origin containing U+0000-U+001F control characters, hostile topOrigin, spec field order with and without topOrigin, and a full round-trip.

Test plan

  • cargo build
  • cargo test --lib (159 passed, including 11 in client_data::tests)
  • cargo fmt --check
  • cargo clippy --lib --all-features --no-deps -- -D warnings

Refs: WebAuthn L3 §5.8.1.2 (CCDToString); audit dossiers D-01, D-02, D-04, B-10, H-04, H-05.

Base automatically changed from rpid-suffix-validation to master May 12, 2026 17:46
ClientData::to_json hand-rolled a JSON object with format!(), concatenating
the origin and topOrigin strings unescaped. An origin containing a double
quote, backslash, or U+0000-U+001F produced malformed JSON, and a hostile
origin like 'https://example.com","origin":"https://attacker.com'
yielded a document with two 'origin' keys.

WebAuthn L3 §5.8.1.2 requires strings be encoded via CCDToString, which is
a strict subset of RFC 8259 string-escape rules. Route serialization
through a serde-derived struct that mirrors the spec field order (type,
challenge, origin, topOrigin?, crossOrigin) so serde_json applies the
correct escapes.

Add regression tests covering hostile origins and topOrigins (double
quote, backslash, control characters), spec-conformant field ordering
with and without topOrigin, and a full round-trip.
@AlfioEmanueleFresta AlfioEmanueleFresta force-pushed the fix/webauthn-clientdata-escaping branch from de3d393 to 2fbfa63 Compare May 12, 2026 18:38
@AlfioEmanueleFresta AlfioEmanueleFresta marked this pull request as ready for review May 12, 2026 18:38
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.

1 participant