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

WebAuthn L3 Passkey Device-Bound Attestation and Conditional Mediation Verification

Enforces strict validation of WebAuthn Level 3 device-bound passkeys to mitigate unauthorized sync and credential-phishing attacks. Mandates server-side cryptographic verification of authenticator data flags (User Presence, User Verification, Backup State, Backup Eligibility) and requires client-side conditional UI mediation checks backed by AbortSignal lifecycle management.

Prohibited Anti-Pattern: Accepting Synced Multi-Device Passkeys for High-Assurance Workflows and Unmediated Autofill Requests

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: WebAuthn L3 Passkey Device-Bound Attestation and Conditional Mediation Verification - Enforces strict validation of WebAuthn Level 3 device-bound passkeys to mitigate unauthorized sync and credential-phishing attacks. Mandates server-side cryptographic verification of authenticator data flags (User Presence, User Verification, Backup State, Backup Eligibility) and requires client-side conditional UI mediation checks backed by AbortSignal lifecycle management.
globs: src/auth/**/*.{ts,tsx}, src/server/auth/**/*.{ts,js}, src/api/webauthn/**/*.{ts,js}, src/components/auth/**/*.{ts,tsx}, src/lib/auth/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/webauthn-l3-device-bound-attestation-conditional-mediation"
---

# WebAuthn L3 Passkey Device-Bound Attestation and Conditional Mediation Verification

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Accepting Synced Multi-Device Passkeys for High-Assurance Workflows and Unmediated Autofill Requests

## System Constraints
You are a Principal Security Architect enforcing WebAuthn Level 3 specifications, FIDO2 invariants, and Conditional UI Autofill security. Reject any implementation that blindly accepts multi-device credentials for high-assurance device-bound targets, fails to enforce User Verification (UV) and User Presence (UP) flags on authData bytes, omits Backup Eligibility (BE) and Backup State (BS) flag audits, or executes conditional mediation without an AbortController and feature detection.

## Strict Guidelines
- Engineers MUST ALWAYS verify User Verification (UV=1, bit 2) and User Presence (UP=1, bit 0) in the raw authenticator data flags byte during registration and assertion verification.
- Engineers MUST ALWAYS inspect Backup Eligibility (BE, bit 3) and Backup State (BS, bit 4) flags; for device-bound security tiers, reject credentials where BE is 1 or enforce explicit tagging of synced passkeys in persistent storage.
- Engineers MUST verify the clientDataJSON challenge using constant-time comparisons against cryptographically secure session-bound nonces with strict expiration (<= 120 seconds).
- Client code MUST check 'PublicKeyCredential.isConditionalMediationAvailable()' before attempting 'mediation: "conditional"' and MUST associate each conditional request with an active AbortController signal.
- Services MUST enforce RP ID matching against the fully qualified origin and strictly reject any wildcard origins or mismatched port schemes.
- Engineers MUST NOT accept 'none' attestation for high-assurance registration flows requiring cryptographic device binding (enterprise/direct attestation verification required).

## Bad vs Good Implementations
### Server-Side Authenticator Data Flag and Attestation Verification

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The handler performs an insecure challenge comparison vulnerable to timing attacks and completely bypasses authenticatorData flag bitmask inspection. It accepts unverified (UV=0), unpresent (UP=0), or multi-device synced (BE=1, BS=1) credentials without validation.
```typescript
import type { Request, Response } from 'express';

export async function verifyAssertion(req: Request, res: Response) {
  const { credential, expectedChallenge } = req.body;
  // Flaw: Decoding clientDataJSON challenge without constant-time check
  const clientData = JSON.parse(Buffer.from(credential.response.clientDataJSON, 'base64url').toString('utf8'));
  if (clientData.challenge !== expectedChallenge) {
    return res.status(400).send('Invalid challenge');
  }
  // Flaw: Blindly assuming user is verified without parsing authenticatorData flags (UP/UV/BE/BS)
  // Allows unverified or synced credentials in high-assurance device-bound flow
  await db.users.markAuthenticated({ credentialId: credential.id });
  return res.json({ ok: true });
}
```

#### Production Standard (Correct)
> **Standard**: Implements full WebAuthn Level 3 spec conformance: uses timing-safe challenge comparison, validates the 32-byte RP ID hash, and inspects bit flags (UP, UV, BE, BS) to reject multi-device synced passkeys on high-assurance endpoints.
```typescript
import { timingSafeEqual } from 'node:crypto';
import type { Request, Response } from 'express';

interface AuthenticatorFlags {
  userPresent: boolean;
  userVerified: boolean;
  backupEligible: boolean;
  backupState: boolean;
}

function parseAuthDataFlags(authData: Buffer): AuthenticatorFlags {
  // Byte 32 holds the bit flags per WebAuthn Level 3 specification
  const flags = authData[32];
  return {
    userPresent: (flags & 0x01) !== 0,
    userVerified: (flags & 0x04) !== 0,
    backupEligible: (flags & 0x08) !== 0,
    backupState: (flags & 0x10) !== 0,
  };
}

export async function verifyDeviceBoundAssertion(req: Request, res: Response) {
  const { credential, expectedChallenge, expectedOrigin, expectedRPIDHash } = req.body;

  const clientData = JSON.parse(Buffer.from(credential.response.clientDataJSON, 'base64url').toString('utf8'));
  if (clientData.type !== 'webauthn.get' || clientData.origin !== expectedOrigin) {
    return res.status(403).json({ error: 'Origin mismatch or invalid type' });
  }

  const receivedChallenge = Buffer.from(clientData.challenge, 'base64url');
  const expectedChallengeBuf = Buffer.from(expectedChallenge, 'base64url');
  if (receivedChallenge.length !== expectedChallengeBuf.length || !timingSafeEqual(receivedChallenge, expectedChallengeBuf)) {
    return res.status(400).json({ error: 'Challenge verification failed' });
  }

  const authData = Buffer.from(credential.response.authenticatorData, 'base64url');
  const rpIdHash = authData.subarray(0, 32);
  if (!timingSafeEqual(rpIdHash, expectedRPIDHash)) {
    return res.status(403).json({ error: 'RP ID Hash mismatch' });
  }

  const flags = parseAuthDataFlags(authData);
  // Enforce Level 3 Invariants: UP and UV MUST be true
  if (!flags.userPresent || !flags.userVerified) {
    return res.status(401).json({ error: 'User Presence and Verification required' });
  }

  // Enforce device-bound invariant: credential must NOT be backed up or eligible for sync
  if (flags.backupEligible || flags.backupState) {
    return res.status(403).json({ error: 'Device-bound hardware passkey required. Synced passkeys rejected.' });
  }

  await db.users.recordAssertionSuccess({ credentialId: credential.id, signCount: authData.readUInt32BE(33) });
  return res.json({ ok: true });
}
```

### Client-Side Conditional Mediation Lifecycle and Abort Signal Handling

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Calling get() with conditional mediation without feature verification crashes unsupported browsers, and omitting an AbortSignal prevents proper cancellation during route changes, modal closes, or modal fallback prompts.
```typescript
export function initAutofillPasskey() {
  // Flaw: Invokes conditional mediation without checking availability
  // Flaw: No AbortController leads to unhandled rejection leaks when navigating or re-authenticating
  navigator.credentials.get({
    publicKey: {
      challenge: new Uint8Array([1, 2, 3]),
    },
    mediation: 'conditional',
  } as CredentialRequestOptions);
}
```

#### Production Standard (Correct)
> **Standard**: Properly gates invocation with 'PublicKeyCredential.isConditionalMediationAvailable()', attaches a robust AbortController to cleanly abort stale conditional loops, and gracefully handles DOMException AbortErrors.
```typescript
export class ConditionalPasskeyManager {
  private abortController: AbortController | null = null;

  public async startAutofill(
    publicKeyOptions: PublicKeyCredentialRequestOptions,
    onSuccess: (cred: PublicKeyCredential) => Promise<void>,
    onError: (err: Error) => void
  ): Promise<void> {
    if (typeof window === 'undefined' || !window.PublicKeyCredential) {
      return;
    }

    const isAvailable =
      typeof PublicKeyCredential.isConditionalMediationAvailable === 'function' &&
      (await PublicKeyCredential.isConditionalMediationAvailable());

    if (!isAvailable) {
      return;
    }

    this.cancelActiveRequest();
    this.abortController = new AbortController();

    try {
      const credential = await navigator.credentials.get({
        publicKey: publicKeyOptions,
        mediation: 'conditional',
        signal: this.abortController.signal,
      });

      if (credential && credential instanceof PublicKeyCredential) {
        await onSuccess(credential);
      }
    } catch (err: unknown) {
      if (err instanceof DOMException && err.name === 'AbortError') {
        // Expected cleanup cancellation
        return;
      }
      onError(err instanceof Error ? err : new Error(String(err)));
    }
  }

  public cancelActiveRequest(): void {
    if (this.abortController) {
      this.abortController.abort();
      this.abortController = null;
    }
  }
}
```

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 Passkey Device-Bound Attestation and Conditional Mediation Verification

WebAuthn L3 Passkey Device-Bound Attestation and Conditional Mediation Verification defines an industrial-grade behavioral standard for security engineering. Enforces strict validation of WebAuthn Level 3 device-bound passkeys to mitigate unauthorized sync and credential-phishing attacks. Mandates server-side cryptographic verification of authenticator data flags (User Presence, User Verification, Backup State, Backup Eligibility) and requires client-side conditional UI mediation checks backed by AbortSignal lifecycle management. 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: Accepting Synced Multi-Device Passkeys for High-Assurance Workflows and Unmediated Autofill Requests 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 DriftAccepting Synced Multi-Device Passkeys for High-Assurance Workflows and Unmediated Autofill RequestsCritical
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 verify User Verification (UV=1, bit 2) and User Presence (UP=1, bit 0) in the raw authenticator data flags byte during registration and assertion verification.

Engineers MUST ALWAYS verify User Verification (UV=1, bit 2) and User Presence (UP=1, bit 0) in the raw authenticator data flags byte during registration and assertion verification.

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 ALWAYS inspect Backup Eligibility (BE, bit 3) and Backup State (BS, bit 4) flags

Engineers MUST ALWAYS inspect Backup Eligibility (BE, bit 3) and Backup State (BS, bit 4) flags; for device-bound security tiers, reject credentials where BE is 1 or enforce explicit tagging of synced passkeys in persistent storage.

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

Engineers MUST verify the clientDataJSON challenge using constant-time comparisons against cryptographically secure session-bound nonces with strict expiration (<= 120 seconds).

Engineers MUST verify the clientDataJSON challenge using constant-time comparisons against cryptographically secure session-bound nonces with strict expiration (<= 120 seconds).

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

Client code MUST check 'PublicKeyCredential.isConditionalMediationAvailable()' before attempting 'mediation

Client code MUST check 'PublicKeyCredential.isConditionalMediationAvailable()' before attempting 'mediation: "conditional"' and MUST associate each conditional request with an active AbortController signal.

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 enforce RP ID matching against the fully qualified origin and strictly reject any wildcard origins or mismatched port schemes.

Services MUST enforce RP ID matching against the fully qualified origin and strictly reject any wildcard origins or mismatched port schemes.

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

Engineers MUST NOT accept 'none' attestation for high-assurance registration flows requiring cryptographic device binding (enterprise/direct attestation verification required).

Engineers MUST NOT accept 'none' attestation for high-assurance registration flows requiring cryptographic device binding (enterprise/direct attestation verification 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.
Technical Questions & Answers

Frequently Asked Technical Questions

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

Q:Why is WebAuthn L3 Passkey Device-Bound Attestation and Conditional Mediation Verification critical for AI coding assistants?

Enforces strict validation of WebAuthn Level 3 device-bound passkeys to mitigate unauthorized sync and credential-phishing attacks. Mandates server-side cryptographic verification of authenticator data flags (User Presence, User Verification, Backup State, Backup Eligibility) and requires client-side conditional UI mediation checks backed by AbortSignal lifecycle management. 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 (Accepting Synced Multi-Device Passkeys for High-Assurance Workflows and Unmediated Autofill Requests) 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