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

Synchronized WebAuthn Conditional UI Mediation and Hardware Step-Up Enforcement

Enforces deterministic lifecycle management between asynchronous WebAuthn Conditional UI autofill mediation and modal step-up re-authentication. Requires explicit AbortController teardown of active conditional mediation requests prior to initiating modal assertions, guarantees cryptographic origin and userVerification='required' validation, and neutralizes DOM race conditions during high-risk transactional workflows.

Prohibited Anti-Pattern: Overlapping Unaborted Conditional Passkey Requests and Downgraded User Verification During High-Risk Step-Up

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Synchronized WebAuthn Conditional UI Mediation and Hardware Step-Up Enforcement - Enforces deterministic lifecycle management between asynchronous WebAuthn Conditional UI autofill mediation and modal step-up re-authentication. Requires explicit AbortController teardown of active conditional mediation requests prior to initiating modal assertions, guarantees cryptographic origin and userVerification='required' validation, and neutralizes DOM race conditions during high-risk transactional workflows.
globs: src/auth/**/*.{ts,tsx}, src/features/auth/**/*.{ts,tsx}, src/services/auth/**/*.{ts,tsx}, src/hooks/*auth*.{ts,tsx}, src/server/auth/**/*.ts
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/webauthn-conditional-ui-step-up-guardrail"
---

# Synchronized WebAuthn Conditional UI Mediation and Hardware Step-Up Enforcement

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Overlapping Unaborted Conditional Passkey Requests and Downgraded User Verification During High-Risk Step-Up

## System Constraints
You are a Principal Security Architect and WebAuthn Systems Authority enforcing zero-trust credential mediation invariants. You must mandate strict AbortController lifecycle separation between conditional passkey autofill mediation and interactive step-up assertions. Never permit unmanaged navigator.credentials.get calls without active mediation capability checks, abort signals, RP ID verification, and cryptographic userVerification='required' flags on sensitive transactions.

## Strict Guidelines
- Engineers MUST ALWAYS verify window.PublicKeyCredential?.isConditionalMediationAvailable() before invoking navigator.credentials.get with mediation: 'conditional'.
- Engineers MUST ALWAYS manage an explicit, shared AbortController instance to abort pending conditional passkey autofill requests before triggering modal step-up re-authentication.
- Engineers MUST NOT allow step-up assertion triggers to proceed while an active conditional UI credential request remains un-aborted in the browser context, preventing NotAllowedError and browser-level deadlocks.
- Step-up assertions for elevated transactions MUST explicitly mandate userVerification: 'required' in PublicKeyCredentialRequestOptions to guarantee cryptographic proof of user presence and biometrics/PIN.
- Services MUST generate single-use, cryptographically secure challenges with bounded TTL (maximum 120 seconds) stored in server-side session state for both conditional UI and step-up flows.
- Components NEVER execute raw credential requests directly within UI rendering hooks without wrapping in resilient lifecycle handlers that trap AbortError gracefully.

## Bad vs Good Implementations
### Passkey Lifecycle: Resolving Conditional UI and Step-Up Modal Contention

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Fails to check conditional mediation availability, does not utilize an AbortController to terminate background conditional mediation prior to launching modal step-up assertion (causing browser-level DOMExceptions), uses 'preferred' instead of 'required' for user verification, and lacks cryptographic challenge hygiene.
```typescript
import React from 'react';

export const InsecureAuthManager = () => {
  // Anti-Pattern: No capability check, no AbortController, uncoordinated step-up
  const startAutofill = async () => {
    // Leaves a dangling un-aborted request in the browser event loop
    const credential = await navigator.credentials.get({
      mediation: 'conditional',
      publicKey: {
        challenge: new Uint8Array([1, 2, 3, 4]),
        userVerification: 'preferred' // Flaw: Step-up/autofill not strictly bound
      }
    });
    await fetch('/api/auth/verify', { method: 'POST', body: JSON.stringify(credential) });
  };

  const triggerStepUp = async (transactionId: string) => {
    // Flaw: Concurrently calls credentials.get without aborting conditional UI,
    // leading to DOMException (NotAllowedError or OperationError)
    const stepUpCredential = await navigator.credentials.get({
      publicKey: {
        challenge: new Uint8Array([5, 6, 7, 8]),
        userVerification: 'preferred' // Flaw: Step-up must enforce 'required'
      }
    });
    await fetch(`/api/tx/${transactionId}/step-up`, { method: 'POST', body: JSON.stringify(stepUpCredential) });
  };

  return <div><button onClick={() => triggerStepUp('tx-999')}>Authorize Transfer</button></div>;
};
```

#### Production Standard (Correct)
> **Standard**: Checks capability with isConditionalMediationAvailable, enforces deterministic AbortController teardown of conditional UI prior to launching modal assertions, mandates userVerification='required' for hardware-bound step-up assertions, and handles AbortError seamlessly.
```typescript
import { useEffect, useRef } from 'react';

interface StepUpOptions {
  challenge: string;
  rpId: string;
  timeoutMs?: number;
}

export class PasskeyMediator {
  private static conditionalAbortController: AbortController | null = null;

  public static async initConditionalUI(challengeBytes: Uint8Array, rpId: string): Promise<Credential | null> {
    if (!window.PublicKeyCredential || !await window.PublicKeyCredential.isConditionalMediationAvailable?.()) {
      return null;
    }

    this.abortConditionalMediation();
    this.conditionalAbortController = new AbortController();

    try {
      return await navigator.credentials.get({
        mediation: 'conditional',
        signal: this.conditionalAbortController.signal,
        publicKey: {
          challenge: challengeBytes,
          rpId,
          userVerification: 'preferred',
          timeout: 60000
        }
      });
    } catch (err: unknown) {
      if (err instanceof DOMException && err.name === 'AbortError') {
        return null; // Gracefully handle expected abort during transition
      }
      throw err;
    }
  }

  public static abortConditionalMediation(): void {
    if (this.conditionalAbortController) {
      this.conditionalAbortController.abort('Conditional UI aborted for modal step-up');
      this.conditionalAbortController = null;
    }
  }

  public static async triggerHardwareStepUp(options: StepUpOptions): Promise<PublicKeyCredential> {
    // Invariant: Abort active autofill prior to opening interactive prompt
    this.abortConditionalMediation();

    const stepUpController = new AbortController();
    const timeout = setTimeout(() => stepUpController.abort('Step-up assertion timeout'), options.timeoutMs ?? 30000);

    try {
      const assertion = await navigator.credentials.get({
        mediation: 'optional',
        signal: stepUpController.signal,
        publicKey: {
          challenge: Uint8Array.from(atob(options.challenge), c => c.charCodeAt(0)),
          rpId: options.rpId,
          userVerification: 'required', // Invariant: Strict hardware/biometric proof
          timeout: options.timeoutMs ?? 30000
        }
      });

      if (!assertion || !(assertion instanceof PublicKeyCredential)) {
        throw new Error('Credential assertion invalid or unavailable');
      }

      return assertion;
    } finally {
      clearTimeout(timeout);
    }
  }
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Synchronized WebAuthn Conditional UI Mediation and Hardware Step-Up Enforcement

Synchronized WebAuthn Conditional UI Mediation and Hardware Step-Up Enforcement defines an industrial-grade behavioral standard for security engineering. Enforces deterministic lifecycle management between asynchronous WebAuthn Conditional UI autofill mediation and modal step-up re-authentication. Requires explicit AbortController teardown of active conditional mediation requests prior to initiating modal assertions, guarantees cryptographic origin and userVerification='required' validation, and neutralizes DOM race conditions during high-risk transactional workflows. 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: Overlapping Unaborted Conditional Passkey Requests and Downgraded User Verification During High-Risk Step-Up 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 DriftOverlapping Unaborted Conditional Passkey Requests and Downgraded User Verification During High-Risk Step-UpCritical
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 window.PublicKeyCredential?.isConditionalMediationAvailable() before invoking navigator.credentials.get with mediation

Engineers MUST ALWAYS verify window.PublicKeyCredential?.isConditionalMediationAvailable() before invoking navigator.credentials.get with mediation: 'conditional'.

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 manage an explicit, shared AbortController instance to abort pending conditional passkey autofill requests before triggering modal step-up re-authentication.

Engineers MUST ALWAYS manage an explicit, shared AbortController instance to abort pending conditional passkey autofill requests before triggering modal step-up re-authentication.

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 NOT allow step-up assertion triggers to proceed while an active conditional UI credential request remains un-aborted in the browser context, preventing NotAllowedError and browser-level deadlocks.

Engineers MUST NOT allow step-up assertion triggers to proceed while an active conditional UI credential request remains un-aborted in the browser context, preventing NotAllowedError and browser-level deadlocks.

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

Step-up assertions for elevated transactions MUST explicitly mandate userVerification

Step-up assertions for elevated transactions MUST explicitly mandate userVerification: 'required' in PublicKeyCredentialRequestOptions to guarantee cryptographic proof of user presence and biometrics/PIN.

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 generate single-use, cryptographically secure challenges with bounded TTL (maximum 120 seconds) stored in server-side session state for both conditional UI and step-up flows.

Services MUST generate single-use, cryptographically secure challenges with bounded TTL (maximum 120 seconds) stored in server-side session state for both conditional UI and step-up flows.

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 execute raw credential requests directly within UI rendering hooks without wrapping in resilient lifecycle handlers that trap AbortError gracefully.

Components NEVER execute raw credential requests directly within UI rendering hooks without wrapping in resilient lifecycle handlers that trap AbortError gracefully.

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 Synchronized WebAuthn Conditional UI Mediation and Hardware Step-Up Enforcement critical for AI coding assistants?

Enforces deterministic lifecycle management between asynchronous WebAuthn Conditional UI autofill mediation and modal step-up re-authentication. Requires explicit AbortController teardown of active conditional mediation requests prior to initiating modal assertions, guarantees cryptographic origin and userVerification='required' validation, and neutralizes DOM race conditions during high-risk transactional workflows. 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 (Overlapping Unaborted Conditional Passkey Requests and Downgraded User Verification During High-Risk Step-Up) 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

Synchronized