This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
securitycritical PriorityID: webauthn-conditional-ui-nonce-replay-barrier

WebAuthn Conditional UI Ephemeral Challenge Ledger and Replay Barrier

WebAuthn Conditional Mediation (passkey autofill) initiates asynchronous, prolonged authentication ceremonies that expose relying parties to challenge replay, token exhaustion, and enumeration attacks. To prevent cross-session assertion replays, all challenges issued for conditional UI must be bound to an ephemeral server session, tracked in an atomic single-use ledger, and irreversibly consumed immediately upon receipt before cryptographic verification begins.

Prohibited Anti-Pattern: Persisting Long-Lived Reusable WebAuthn Challenges or Deferring Nonce Consumption Until After Signature Verification

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: WebAuthn Conditional UI Ephemeral Challenge Ledger and Replay Barrier - WebAuthn Conditional Mediation (passkey autofill) initiates asynchronous, prolonged authentication ceremonies that expose relying parties to challenge replay, token exhaustion, and enumeration attacks. To prevent cross-session assertion replays, all challenges issued for conditional UI must be bound to an ephemeral server session, tracked in an atomic single-use ledger, and irreversibly consumed immediately upon receipt before cryptographic verification begins.
globs: src/auth/**/*.{ts,tsx}, src/server/auth/**/*.{ts,tsx}, src/api/auth/**/*.{ts,tsx}, src/services/passkey/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/webauthn-conditional-ui-nonce-replay-barrier"
---

# WebAuthn Conditional UI Ephemeral Challenge Ledger and Replay Barrier

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Persisting Long-Lived Reusable WebAuthn Challenges or Deferring Nonce Consumption Until After Signature Verification

## System Constraints
You are a Principal Security Architect enforcing zero-trust WebAuthn standards. WebAuthn Conditional UI prompts are long-lived and susceptible to assertion interception and replay. You must enforce atomic challenge consumption, strict ephemeral session binding, and constant-time failure handling across all passkey ceremony endpoints.

## Strict Guidelines
- Engineers MUST ALWAYS store issued WebAuthn conditional challenges in an atomic ledger (e.g., Redis via GETDEL or transactional KV) with a strict TTL not exceeding 300 seconds.
- Engineers MUST ALWAYS cryptographically bind the challenge to an ephemeral, HTTP-only, SameSite=Strict cookie session token issued at ceremony generation.
- Services MUST atomically retrieve and delete (burn) the challenge nonce at the start of assertion verification; the nonce MUST be destroyed regardless of whether cryptographic validation succeeds or fails.
- Engineers MUST NOT allow challenge reuse across multiple authentication ceremonies or fall back to client-provided stateless nonces.
- Components NEVER disclose whether a failure occurred due to an invalid challenge, missing user credential, or malformed signature—uniform generic errors MUST be returned to prevent enumeration vectors.
- Services MUST verify that clientDataJSON.type strictly equals 'webauthn.get' and that the decoded challenge matches the ledger entry byte-for-byte in constant time.

## Bad vs Good Implementations
### Atomic Challenge Consumption via Ephemeral Session Ledger

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Reading the challenge without atomic deletion allows race conditions where concurrent requests can replay the same assertion response. If verification fails or throws an exception, the challenge remains live in the session until it expires naturally, allowing credential stuffing retries.
```typescript
import { verifyAuthenticationResponse } from '@simplewebauthn/server';
import type { AuthenticationResponseJSON } from '@simplewebauthn/types';
import type { Request, Response } from 'express';

// ANTI-PATTERN: Challenge is read from a mutable session and only cleared after
// verification succeeds, enabling race-condition replays and concurrent assertions.
export async function verifyConditionalAssertion(req: Request, res: Response) {
  const response: AuthenticationResponseJSON = req.body;
  const expectedChallenge = req.session.currentChallenge;

  if (!expectedChallenge) {
    return res.status(400).json({ error: 'No active challenge found' });
  }

  const verification = await verifyAuthenticationResponse({
    response,
    expectedChallenge,
    expectedOrigin: 'https://example.com',
    expectedRPID: 'example.com',
    authenticator: await getAuthenticator(response.id),
  });

  if (verification.verified) {
    // VULNERABILITY: Nonce remains valid if verification fails or network aborts mid-flight,
    // and concurrent requests with the same challenge can pass before this line executes.
    delete req.session.currentChallenge;
    return res.json({ success: true });
  }

  return res.status(401).json({ error: 'Verification failed' });
}
```

#### Production Standard (Correct)
> **Standard**: Uses Redis `GETDEL` to atomically retrieve and purge the challenge immediately upon entering the assertion handler, neutralizing replay attacks and race conditions. Binds the challenge to a strict `__Host-` scoped cookie and standardizes all error messages to protect against credential enumeration.
```typescript
import { verifyAuthenticationResponse } from '@simplewebauthn/server';
import type { AuthenticationResponseJSON } from '@simplewebauthn/types';
import type { Request, Response } from 'express';
import crypto from 'node:crypto';
import { redis } from '../lib/redis';

const CHALLENGE_PREFIX = 'webauthn:cond_ui:challenge:';

export async function verifyConditionalAssertion(req: Request, res: Response) {
  const sessionToken = req.cookies['__Host-auth-ceremony'];
  const response: AuthenticationResponseJSON = req.body;

  if (!sessionToken || typeof sessionToken !== 'string') {
    return res.status(401).json({ error: 'Invalid authentication context' });
  }

  // ATOMIC CONSUMPTION: Atomically read and delete the nonce in a single operation (GETDEL).
  // Prevents concurrent replay attacks and guarantees single-use even if downstream verification fails.
  const challengeKey = `${CHALLENGE_PREFIX}${sessionToken}`;
  const expectedChallenge = await redis.getdel(challengeKey);

  // Clear the ceremony cookie immediately
  res.clearCookie('__Host-auth-ceremony', { path: '/', httpOnly: true, secure: true, sameSite: 'strict' });

  if (!expectedChallenge) {
    // Uniform error prevents timing-based challenge enumeration
    return res.status(401).json({ error: 'Authentication ceremony expired or already consumed' });
  }

  try {
    const authenticator = await getAuthenticator(response.id);
    if (!authenticator) {
      return res.status(401).json({ error: 'Authentication failed' });
    }

    const verification = await verifyAuthenticationResponse({
      response,
      expectedChallenge,
      expectedOrigin: process.env.AUTH_RP_ORIGIN!,
      expectedRPID: process.env.AUTH_RP_ID!,
      authenticator,
      requireUserVerification: true,
    });

    if (!verification.verified) {
      return res.status(401).json({ error: 'Authentication failed' });
    }

    return res.json({ success: true, userId: authenticator.userId });
  } catch (error) {
    return res.status(401).json({ error: 'Authentication failed' });
  }
}
```

Recommended MCP Servers (mcp-serverlist.com)

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

Architectural Specification & Invariant Rationale

Architectural Invariant Design: WebAuthn Conditional UI Ephemeral Challenge Ledger and Replay Barrier

WebAuthn Conditional UI Ephemeral Challenge Ledger and Replay Barrier defines an industrial-grade behavioral standard for security engineering. WebAuthn Conditional Mediation (passkey autofill) initiates asynchronous, prolonged authentication ceremonies that expose relying parties to challenge replay, token exhaustion, and enumeration attacks. To prevent cross-session assertion replays, all challenges issued for conditional UI must be bound to an ephemeral server session, tracked in an atomic single-use ledger, and irreversibly consumed immediately upon receipt before cryptographic verification begins. 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: Persisting Long-Lived Reusable WebAuthn Challenges or Deferring Nonce Consumption Until After Signature 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 DriftPersisting Long-Lived Reusable WebAuthn Challenges or Deferring Nonce Consumption Until After Signature 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 store issued WebAuthn conditional challenges in an atomic ledger (e.g., Redis via GETDEL or transactional KV) with a strict TTL not exceeding 300 seconds.

Engineers MUST ALWAYS store issued WebAuthn conditional challenges in an atomic ledger (e.g., Redis via GETDEL or transactional KV) with a strict TTL not exceeding 300 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.
2

Engineers MUST ALWAYS cryptographically bind the challenge to an ephemeral, HTTP-only, SameSite=Strict cookie session token issued at ceremony generation.

Engineers MUST ALWAYS cryptographically bind the challenge to an ephemeral, HTTP-only, SameSite=Strict cookie session token issued at ceremony generation.

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

Services MUST atomically retrieve and delete (burn) the challenge nonce at the start of assertion verification

Services MUST atomically retrieve and delete (burn) the challenge nonce at the start of assertion verification; the nonce MUST be destroyed regardless of whether cryptographic validation succeeds or fails.

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

Engineers MUST NOT allow challenge reuse across multiple authentication ceremonies or fall back to client-provided stateless nonces.

Engineers MUST NOT allow challenge reuse across multiple authentication ceremonies or fall back to client-provided stateless nonces.

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

Components NEVER disclose whether a failure occurred due to an invalid challenge, missing user credential, or malformed signature—uniform generic errors MUST be returned to prevent enumeration vectors.

Components NEVER disclose whether a failure occurred due to an invalid challenge, missing user credential, or malformed signature—uniform generic errors MUST be returned to prevent enumeration vectors.

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

Services MUST verify that clientDataJSON.type strictly equals 'webauthn.get' and that the decoded challenge matches the ledger entry byte-for-byte in constant time.

Services MUST verify that clientDataJSON.type strictly equals 'webauthn.get' and that the decoded challenge matches the ledger entry byte-for-byte in constant time.

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 Conditional UI Ephemeral Challenge Ledger and Replay Barrier critical for AI coding assistants?

WebAuthn Conditional Mediation (passkey autofill) initiates asynchronous, prolonged authentication ceremonies that expose relying parties to challenge replay, token exhaustion, and enumeration attacks. To prevent cross-session assertion replays, all challenges issued for conditional UI must be bound to an ephemeral server session, tracked in an atomic single-use ledger, and irreversibly consumed immediately upon receipt before cryptographic verification begins. 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 (Persisting Long-Lived Reusable WebAuthn Challenges or Deferring Nonce Consumption Until After Signature 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