This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
securitycritical PriorityID: webauthn-l3-conditional-mediation-attestation-verifier

WebAuthn L3 Conditional Mediation Fallback and Cryptographic Attestation Verification

Enforces strict zero-trust validation of WebAuthn clientDataJSON, authenticatorData flags (UP/UV), and cryptographic attestation statements during registration and assertion. Mandates clean AbortController orchestration for conditional mediation (passkey autofill) to prevent UI lockouts and race conditions during modal fallbacks.

Prohibited Anti-Pattern: Silent degradation to unauthenticated fallback and lax clientDataJSON or attestation verification

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: WebAuthn L3 Conditional Mediation Fallback and Cryptographic Attestation Verification - Enforces strict zero-trust validation of WebAuthn clientDataJSON, authenticatorData flags (UP/UV), and cryptographic attestation statements during registration and assertion. Mandates clean AbortController orchestration for conditional mediation (passkey autofill) to prevent UI lockouts and race conditions during modal fallbacks.
globs: src/auth/**/*.{ts,tsx}, src/server/auth/**/*.ts, pages/api/auth/**/*.ts, app/api/auth/**/*.ts
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/webauthn-l3-conditional-mediation-attestation-verifier"
---

# WebAuthn L3 Conditional Mediation Fallback and Cryptographic Attestation Verification

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Silent degradation to unauthenticated fallback and lax clientDataJSON or attestation verification

## System Constraints
You are a Principal Security Architect enforcing FIDO2 WebAuthn Level 3 specifications. Reject unauthenticated autofill degradations, unverified clientDataJSON invariants, and bypassed authenticatorData flags.

## Strict Guidelines
- Engineers MUST ALWAYS cleanly abort active conditional mediation (autofill) AbortControllers before initiating a modal (explicit user gesture) WebAuthn credential ceremony.
- Engineers MUST NOT rely on raw JSON parsing without validating that clientDataJSON.type matches the exact ceremony ('webauthn.create' or 'webauthn.get'), challenge matches the cryptographically random session state, and origin matches the exact configured Relying Party (RP) origin.
- Code MUST verify that clientDataJSON.crossOrigin is explicitly false (or strictly validated against an allowed cross-origin list when using cross-origin iframes).
- Services MUST verify authenticatorData flags: User Presence (UP bit 0) MUST always be 1; User Verification (UV bit 2) MUST be 1 when userVerification is set to 'required'.
- Services MUST compute the SHA-256 hash of the expected rpId and verify it matches authData.rpIdHash byte-for-byte to prevent credential cross-site replay.
- Components NEVER swallow WebAuthn AbortError or NotAllowedError exceptions blindly; AbortErrors resulting from conditional mediation replacement must be handled without triggering UI failure states.

## Bad vs Good Implementations
### Client-Side: Safe Conditional UI Mediation with Abort Signal Handshake

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Launching a modal credential request while a conditional mediation request is unresolved without aborting it triggers an invalid state error (DOMException: NotAllowedError) in Chromium/WebKit browsers, rendering passkeys unusable.
```typescript
async function startAuth() {
  // Anti-pattern: No AbortController management; unhandled races
  if (window.PublicKeyCredential && await PublicKeyCredential.isConditionalMediationAvailable()) {
    navigator.credentials.get({
      publicKey: { challenge: new Uint8Array([1, 2, 3]) },
      mediation: 'conditional'
    });
  }
  // When user clicks explicit 'Sign in' button:
  document.getElementById('modal-btn')!.onclick = async () => {
    // Fails with NotAllowedError or blocks because conditional ceremony is still pending
    const cred = await navigator.credentials.get({
      publicKey: { challenge: new Uint8Array([4, 5, 6]) },
      mediation: 'optional'
    });
    await fetch('/api/verify', { method: 'POST', body: JSON.stringify(cred) });
  };
}
```

#### Production Standard (Correct)
> **Standard**: Properly tracks the conditional mediation cycle with an AbortController and cancels it before triggering explicit modal authentication, handling the resulting AbortError safely.
```typescript
class PasskeyClient {
  private conditionalAbortController: AbortController | null = null;

  async initConditionalAutofill(options: CredentialRequestOptions): Promise<Credential | null> {
    if (!window.PublicKeyCredential || !PublicKeyCredential.isConditionalMediationAvailable) {
      return null;
    }
    const isAvailable = await PublicKeyCredential.isConditionalMediationAvailable();
    if (!isAvailable) return null;

    this.conditionalAbortController = new AbortController();
    try {
      return await navigator.credentials.get({
        ...options,
        signal: this.conditionalAbortController.signal,
        mediation: 'conditional'
      });
    } catch (err: unknown) {
      if (err instanceof DOMException && err.name === 'AbortError') {
        return null; // Gracefully handle intentional teardown for modal switch
      }
      throw err;
    }
  }

  async triggerModalAuthentication(options: CredentialRequestOptions): Promise<Credential | null> {
    // Explicitly cancel conditional ceremony prior to launching modal prompt
    if (this.conditionalAbortController) {
      this.conditionalAbortController.abort();
      this.conditionalAbortController = null;
    }
    return await navigator.credentials.get({
      ...options,
      mediation: 'optional'
    });
  }
}
```

### Server-Side: Invariant Verification of clientDataJSON and AuthenticatorData

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Fails to verify clientDataJSON type, origin, and crossOrigin flags. Fails to verify SHA-256 rpIdHash and flags in authenticatorData (UP and UV bits), allowing cross-origin replay attacks and platforms bypassing user verification.
```typescript
export function verifyAssertion(response: { clientDataJSON: string; authenticatorData: string }, expectedChallenge: string) {
  // Anti-pattern: Missing origin check, missing type validation, missing UP/UV flag validation
  const rawClientData = Buffer.from(response.clientDataJSON, 'base64url').toString('utf-8');
  const clientData = JSON.parse(rawClientData);

  if (clientData.challenge !== expectedChallenge) {
    throw new Error('Challenge mismatch');
  }
  // Authenticator data flags and rpIdHash are completely ignored!
  return true;
}
```

#### Production Standard (Correct)
> **Standard**: Validates all critical WebAuthn Level 3 requirements: clientDataJSON type, challenge, origin, crossOrigin flag, exact SHA-256 rpIdHash match, and cryptographic byte flags for User Presence (UP) and User Verification (UV).
```typescript
import crypto from 'node:crypto';

interface ClientDataJSON {
  type: string;
  challenge: string;
  origin: string;
  crossOrigin?: boolean;
}

export function verifyAssertionResponse(
  rawClientDataJSON: Uint8Array,
  rawAuthData: Uint8Array,
  expectedChallenge: string,
  expectedOrigin: string,
  expectedRpId: string,
  requireUserVerification: boolean = true
): boolean {
  // 1. Parse and validate clientDataJSON
  const clientData: ClientDataJSON = JSON.parse(Buffer.from(rawClientDataJSON).toString('utf-8'));
  if (clientData.type !== 'webauthn.get') {
    throw new Error(`Invalid ceremony type: expected 'webauthn.get', got '${clientData.type}'`);
  }
  if (clientData.challenge !== expectedChallenge) {
    throw new Error('Challenge mismatch');
  }
  if (clientData.origin !== expectedOrigin) {
    throw new Error(`Origin mismatch: expected '${expectedOrigin}', got '${clientData.origin}'`);
  }
  if (clientData.crossOrigin === true) {
    throw new Error('Unauthorized cross-origin WebAuthn assertion detected');
  }

  // 2. Validate authenticatorData structure (minimum 37 bytes)
  if (rawAuthData.length < 37) {
    throw new Error('Malformatted authenticatorData: length < 37 bytes');
  }

  // 3. Verify rpIdHash (first 32 bytes)
  const expectedRpIdHash = crypto.createHash('sha256').update(expectedRpId).digest();
  const actualRpIdHash = Buffer.from(rawAuthData.subarray(0, 32));
  if (!expectedRpIdHash.equals(actualRpIdHash)) {
    throw new Error('RP ID hash mismatch: credential bound to different domain');
  }

  // 4. Verify Flags (byte 32)
  const flags = rawAuthData[32];
  const userPresent = (flags & 0x01) !== 0; // Bit 0
  const userVerified = (flags & 0x04) !== 0; // Bit 2

  if (!userPresent) {
    throw new Error('User Presence (UP) flag not set by authenticator');
  }
  if (requireUserVerification && !userVerified) {
    throw new Error('User Verification (UV) flag required but not asserted');
  }

  return true;
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: WebAuthn L3 Conditional Mediation Fallback and Cryptographic Attestation Verification

WebAuthn L3 Conditional Mediation Fallback and Cryptographic Attestation Verification defines an industrial-grade behavioral standard for security engineering. Enforces strict zero-trust validation of WebAuthn clientDataJSON, authenticatorData flags (UP/UV), and cryptographic attestation statements during registration and assertion. Mandates clean AbortController orchestration for conditional mediation (passkey autofill) to prevent UI lockouts and race conditions during modal fallbacks. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Silent degradation to unauthenticated fallback and lax clientDataJSON or attestation verification Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftSilent degradation to unauthenticated fallback and lax clientDataJSON or attestation verificationCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS cleanly abort active conditional mediation (autofill) AbortControllers before initiating a modal (explicit user gesture) WebAuthn credential ceremony.

Engineers MUST ALWAYS cleanly abort active conditional mediation (autofill) AbortControllers before initiating a modal (explicit user gesture) WebAuthn credential ceremony.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT rely on raw JSON parsing without validating that clientDataJSON.type matches the exact ceremony ('webauthn.create' or 'webauthn.get'), challenge matches the cryptographically random session state, and origin matches the exact configured Relying Party (RP) origin.

Engineers MUST NOT rely on raw JSON parsing without validating that clientDataJSON.type matches the exact ceremony ('webauthn.create' or 'webauthn.get'), challenge matches the cryptographically random session state, and origin matches the exact configured Relying Party (RP) origin.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Code MUST verify that clientDataJSON.crossOrigin is explicitly false (or strictly validated against an allowed cross-origin list when using cross-origin iframes).

Code MUST verify that clientDataJSON.crossOrigin is explicitly false (or strictly validated against an allowed cross-origin list when using cross-origin iframes).

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Services MUST verify authenticatorData flags

Services MUST verify authenticatorData flags: User Presence (UP bit 0) MUST always be 1; User Verification (UV bit 2) MUST be 1 when userVerification is set to 'required'.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Services MUST compute the SHA-256 hash of the expected rpId and verify it matches authData.rpIdHash byte-for-byte to prevent credential cross-site replay.

Services MUST compute the SHA-256 hash of the expected rpId and verify it matches authData.rpIdHash byte-for-byte to prevent credential cross-site replay.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
6

Components NEVER swallow WebAuthn AbortError or NotAllowedError exceptions blindly

Components NEVER swallow WebAuthn AbortError or NotAllowedError exceptions blindly; AbortErrors resulting from conditional mediation replacement must be handled without triggering UI failure states.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is WebAuthn L3 Conditional Mediation Fallback and Cryptographic Attestation Verification critical for AI coding assistants?

Enforces strict zero-trust validation of WebAuthn clientDataJSON, authenticatorData flags (UP/UV), and cryptographic attestation statements during registration and assertion. Mandates clean AbortController orchestration for conditional mediation (passkey autofill) to prevent UI lockouts and race conditions during modal fallbacks. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Silent degradation to unauthenticated fallback and lax clientDataJSON or attestation verification) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

WebAuthn