This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
securitycritical PriorityID: webauthn-l3-passkey-origin-binding-guardrail

WebAuthn Level 3 Device-Bound Passkey Origin Binding & Iframe Isolation

Enforces strict W3C WebAuthn Level 3 cryptographic verification of Relying Party ID (rpId) and clientDataJSON origin bindings across all passkey registration and authentication ceremonies. Neutralizes cross-origin iframe exfiltration, adversarial session fixation, and federated phishing vectors by mandating top-level document fences and canonical origin matching on the server. Prevents reliance on client-controlled Host headers and insecure iframe delegates without strict Permissions-Policy directives.

Prohibited Anti-Pattern: Trusting Client-Supplied Origin Headers and Permitting WebAuthn in Cross-Origin Iframes

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: WebAuthn Level 3 Device-Bound Passkey Origin Binding & Iframe Isolation - Enforces strict W3C WebAuthn Level 3 cryptographic verification of Relying Party ID (rpId) and clientDataJSON origin bindings across all passkey registration and authentication ceremonies. Neutralizes cross-origin iframe exfiltration, adversarial session fixation, and federated phishing vectors by mandating top-level document fences and canonical origin matching on the server. Prevents reliance on client-controlled Host headers and insecure iframe delegates without strict Permissions-Policy directives.
globs: src/auth/**/*.{ts,tsx}, src/server/auth/**/*.{ts,js}, src/api/auth/**/*.{ts,js}, src/middleware/**/*.{ts,js}, src/routes/auth/**/*.{ts,js}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/webauthn-l3-passkey-origin-binding-guardrail"
---

# WebAuthn Level 3 Device-Bound Passkey Origin Binding & Iframe Isolation

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Trusting Client-Supplied Origin Headers and Permitting WebAuthn in Cross-Origin Iframes

## System Constraints
You are a Principal Security Architect enforcing W3C WebAuthn Level 3 specifications for device-bound passkey registration and assertion ceremonies. You must ensure zero tolerance for relaxed origin validation, dynamic client-dictated RP IDs, and insecure cross-origin credential generation. Every server-side verification must decode and cryptographically bind clientDataJSON origin against an immutable server-side allowlist, verify rpIdHash matches the canonical SHA-256 digest of the expected RP ID, enforce authenticatorData flags (UP and UV), and ensure frontend ceremonies are fenced within top-level browsing contexts protected by Permissions-Policy: publickey-credentials-get=(self).

## Strict Guidelines
- Engineers MUST ALWAYS validate clientDataJSON.origin against an immutable, hardcoded server-side canonical origin allowlist and NEVER derive the expected origin dynamically from incoming Host or X-Forwarded-Host headers.
- Engineers MUST ALWAYS verify that clientDataJSON.type strictly equals 'webauthn.create' during registration and 'webauthn.get' during authentication.
- Engineers MUST ALWAYS verify that authenticatorData.rpIdHash exactly matches the SHA-256 digest of the canonical Relying Party ID (rpId).
- Services MUST verify that authenticatorData flags UP (User Present) and UV (User Verified) are asserted true according to the policy requirements, rejecting assertions with UP=0.
- Components and frontend templates MUST NEVER invoke navigator.credentials.create() or navigator.credentials.get() inside an unisolated cross-origin iframe; they MUST be executed in a top-level secure browsing context (window.top === window.self) or explicitly gated with Permissions-Policy: publickey-credentials-get=(self).
- Services MUST verify clientDataJSON.challenge matches the cryptographically random, ephemeral, session-bound nonce generated server-side and consume it immediately to prevent replay attacks.

## Bad vs Good Implementations
### Server-Side WebAuthn Assertion Verification Guardrail

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The server constructs expectedOrigin and expectedRPID dynamically from the untrusted client-controlled 'Host' header. An attacker hosting a phishing proxy or running inside an insecure frame can point the origin to their own domain, causing the server to accept a fraudulent origin and bypassing RP ID cryptographic isolation.
```typescript
import { Request, Response } from 'express';
import { verifyAuthenticationResponse } from '@simplewebauthn/server';

export async function verifyAssertion(req: Request, res: Response) {
  const { body, session } = req;
  
  // CRITICAL VULNERABILITY: Origin dynamically inferred from client headers (vulnerable to host header spoofing/phishing)
  const dynamicOrigin = `https://${req.get('host')}`;
  const dynamicRPID = req.get('host')?.split(':')[0] || 'localhost';

  const verification = await verifyAuthenticationResponse({
    response: body,
    expectedChallenge: session.currentChallenge,
    expectedOrigin: dynamicOrigin,
    expectedRPID: dynamicRPID,
    authenticator: {
      credentialID: body.id,
      credentialPublicKey: session.userPublicKey,
      counter: session.userCounter
    }
  });

  if (verification.verified) {
    return res.status(200).json({ success: true });
  }
  return res.status(401).json({ error: 'Failed' });
}
```

#### Production Standard (Correct)
> **Standard**: Validates the assertion strictly against static canonical origins and canonical rpId. The challenge is single-use and invalidated immediately. Early validation of clientDataJSON.origin fences unauthorized hosts, and simplewebauthn guarantees cryptographic rpIdHash validation over user presence (UP) and user verification (UV).
```typescript
import { Request, Response } from 'express';
import crypto from 'node:crypto';
import { verifyAuthenticationResponse } from '@simplewebauthn/server';

const CANONICAL_RP_ID = 'identity.production.domain.com' as const;
const CANONICAL_ORIGINS = new Set([
  'https://identity.production.domain.com',
  'https://login.production.domain.com'
]);

export async function verifyAssertion(req: Request, res: Response) {
  const { body, session } = req;
  const challenge = session.currentChallenge;

  if (!challenge || typeof challenge !== 'string') {
    return res.status(400).json({ error: 'Missing or expired registration/login challenge' });
  }

  // Destroy challenge immediately to prevent replay
  session.currentChallenge = undefined;

  // Decode clientDataJSON to perform early invariant check on origin fence
  const clientDataJSON = JSON.parse(
    Buffer.from(body.response.clientDataJSON, 'base64url').toString('utf8')
  );

  if (!CANONICAL_ORIGINS.has(clientDataJSON.origin)) {
    return res.status(403).json({
      error: `Origin mismatch fence violation: ${clientDataJSON.origin}`
    });
  }

  const verification = await verifyAuthenticationResponse({
    response: body,
    expectedChallenge: challenge,
    expectedOrigin: Array.from(CANONICAL_ORIGINS),
    expectedRPID: CANONICAL_RP_ID,
    authenticator: {
      credentialID: body.id,
      credentialPublicKey: session.userPublicKey,
      counter: session.userCounter
    },
    requireUserVerification: true
  });

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

  return res.status(200).json({ success: true, newCounter: verification.authenticationInfo.newCounter });
}
```

### Client-Side Top-Level Frame & Origin Isolation Guardrail

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Fails to inspect whether execution is nested in an unauthorized or cross-origin iframe context, opening the application to clickjacking or cross-origin credential interception when Permissions-Policy headers are not globally hardened.
```typescript
export async function triggerPasskeyAuth(options: CredentialRequestOptions) {
  // Anti-pattern: Invoked blindly without checking top-level browsing context or permissions fence
  const credential = await navigator.credentials.get(options);
  return credential;
}
```

#### Production Standard (Correct)
> **Standard**: Enforces runtime top-level context inspection (window.top === window.self) and secure context validation prior to invoking the WebAuthn API, preventing unauthorized invocation from embedded sub-frames.
```typescript
export async function triggerPasskeyAuth(options: CredentialRequestOptions): Promise<Credential | null> {
  // Invariant Guardrail: WebAuthn must execute only in the top-level browsing context
  if (window.top !== window.self) {
    throw new SecurityError(
      'Invariant Violation: WebAuthn ceremony forbidden within nested browsing contexts (iframes). Top-level context required.'
    );
  }

  if (!window.isSecureContext) {
    throw new SecurityError('WebAuthn Level 3 mandates a Secure Context (HTTPS or localhost).');
  }

  if (!navigator.credentials || typeof navigator.credentials.get !== 'function') {
    throw new Error('WebAuthn API is not supported on this platform/browser.');
  }

  return await navigator.credentials.get(options);
}
```

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 Level 3 Device-Bound Passkey Origin Binding & Iframe Isolation

WebAuthn Level 3 Device-Bound Passkey Origin Binding & Iframe Isolation defines an industrial-grade behavioral standard for security engineering. Enforces strict W3C WebAuthn Level 3 cryptographic verification of Relying Party ID (rpId) and clientDataJSON origin bindings across all passkey registration and authentication ceremonies. Neutralizes cross-origin iframe exfiltration, adversarial session fixation, and federated phishing vectors by mandating top-level document fences and canonical origin matching on the server. Prevents reliance on client-controlled Host headers and insecure iframe delegates without strict Permissions-Policy directives. 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: Trusting Client-Supplied Origin Headers and Permitting WebAuthn in Cross-Origin Iframes 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 DriftTrusting Client-Supplied Origin Headers and Permitting WebAuthn in Cross-Origin IframesCritical
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 validate clientDataJSON.origin against an immutable, hardcoded server-side canonical origin allowlist and NEVER derive the expected origin dynamically from incoming Host or X-Forwarded-Host headers.

Engineers MUST ALWAYS validate clientDataJSON.origin against an immutable, hardcoded server-side canonical origin allowlist and NEVER derive the expected origin dynamically from incoming Host or X-Forwarded-Host headers.

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 verify that clientDataJSON.type strictly equals 'webauthn.create' during registration and 'webauthn.get' during authentication.

Engineers MUST ALWAYS verify that clientDataJSON.type strictly equals 'webauthn.create' during registration and 'webauthn.get' during 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 ALWAYS verify that authenticatorData.rpIdHash exactly matches the SHA-256 digest of the canonical Relying Party ID (rpId).

Engineers MUST ALWAYS verify that authenticatorData.rpIdHash exactly matches the SHA-256 digest of the canonical Relying Party ID (rpId).

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 that authenticatorData flags UP (User Present) and UV (User Verified) are asserted true according to the policy requirements, rejecting assertions with UP=0.

Services MUST verify that authenticatorData flags UP (User Present) and UV (User Verified) are asserted true according to the policy requirements, rejecting assertions with UP=0.

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 and frontend templates MUST NEVER invoke navigator.credentials.create() or navigator.credentials.get() inside an unisolated cross-origin iframe

Components and frontend templates MUST NEVER invoke navigator.credentials.create() or navigator.credentials.get() inside an unisolated cross-origin iframe; they MUST be executed in a top-level secure browsing context (window.top === window.self) or explicitly gated with Permissions-Policy: publickey-credentials-get=(self).

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 clientDataJSON.challenge matches the cryptographically random, ephemeral, session-bound nonce generated server-side and consume it immediately to prevent replay attacks.

Services MUST verify clientDataJSON.challenge matches the cryptographically random, ephemeral, session-bound nonce generated server-side and consume it immediately to prevent replay attacks.

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 Level 3 Device-Bound Passkey Origin Binding & Iframe Isolation critical for AI coding assistants?

Enforces strict W3C WebAuthn Level 3 cryptographic verification of Relying Party ID (rpId) and clientDataJSON origin bindings across all passkey registration and authentication ceremonies. Neutralizes cross-origin iframe exfiltration, adversarial session fixation, and federated phishing vectors by mandating top-level document fences and canonical origin matching on the server. Prevents reliance on client-controlled Host headers and insecure iframe delegates without strict Permissions-Policy directives. 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 (Trusting Client-Supplied Origin Headers and Permitting WebAuthn in Cross-Origin Iframes) 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