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

WebAuthn Level 3 PRF Hardware-Anchored Symmetric Key Derivation Protocol

Enforces strict cryptographic hygiene when using the WebAuthn Level 3 PRF (Pseudo-Random Function) extension for zero-knowledge client-side encryption. Requires non-extractable Web Crypto API key handles, domain-separated HKDF salt inputs, resilient extension capability checks, and explicit volatile memory zeroization to prevent key exfiltration via DOM XSS.

Prohibited Anti-Pattern: Deriving client encryption keys from authenticator signatures or retaining extractable raw PRF outputs in browser heap

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: WebAuthn Level 3 PRF Hardware-Anchored Symmetric Key Derivation Protocol - Enforces strict cryptographic hygiene when using the WebAuthn Level 3 PRF (Pseudo-Random Function) extension for zero-knowledge client-side encryption. Requires non-extractable Web Crypto API key handles, domain-separated HKDF salt inputs, resilient extension capability checks, and explicit volatile memory zeroization to prevent key exfiltration via DOM XSS.
globs: src/**/*.{ts,tsx}, lib/**/*.{ts,tsx}, packages/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/webauthn-l3-prf-symmetric-key-derivation-guardrail"
---

# WebAuthn Level 3 PRF Hardware-Anchored Symmetric Key Derivation Protocol

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Deriving client encryption keys from authenticator signatures or retaining extractable raw PRF outputs in browser heap

## System Constraints
You are a Principal Security Architect enforcing the WebAuthn Level 3 PRF (Pseudo-Random Function / hmac-secret) client-side key derivation standard. You must prevent memory exfiltration of hardware-derived entropy, prohibit derivation of symmetric keys from signature assertions, mandate cryptographically secure domain-separated salts, and enforce non-extractable CryptoKey material.

## Strict Guidelines
- Engineers MUST ALWAYS request the WebAuthn PRF extension via `extensions: { prf: { eval: { first: saltBuffer } } }` during `navigator.credentials.get` calls.
- Engineers MUST NOT derive symmetric encryption keys from WebAuthn assertion signatures (`response.signature`), as signatures are verifiable by relying party servers and lack zero-knowledge confidentiality.
- Code MUST verify `clientExtensionResults.prf?.results?.first` exists and is an `ArrayBuffer` before attempting downstream cryptographic operations.
- Code MUST import the raw PRF entropy into `window.crypto.subtle.importKey` with `extractable: false` and the `'HKDF'` algorithm immediately upon retrieval.
- Code MUST zeroize the transient PRF `Uint8Array` buffer using `.fill(0)` immediately after importing into WebCrypto to minimize exposure window against browser memory dump attacks or prototype pollution / XSS.
- Engineers MUST ALWAYS enforce domain separation by mixing a unique context string and user/account identifier into the PRF evaluation salt using HKDF or HMAC-SHA-256 before passing to the authenticator.
- Components NEVER expose the raw derived key, intermediate PRF output, or base64 representations thereof to reactive UI state (e.g., Redux, Pinia, React state) or persistent web storage (localStorage, sessionStorage, IndexedDB).

## Bad vs Good Implementations
### Hardware PRF Symmetric Key Derivation with HKDF and Memory Zeroization

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Derives a symmetric key directly from a WebAuthn signature buffer instead of using the PRF extension. The signature is sent to and verifiable by the server, completely breaking zero-knowledge guarantees. Additionally, the key is imported as extractable (`extractable: true`) and dumped into `localStorage`, exposing user encryption keys directly to any XSS payload.
```typescript
import { startAuthentication } from '@simplewebauthn/browser';

export async function deriveKeyInsecure(assertionResponse: any) {
  // Anti-pattern 1: Deriving encryption key from the assertion signature
  // Signatures are transmitted to servers and lack zero-knowledge properties
  const rawSignature = new Uint8Array(assertionResponse.response.signature);
  
  // Anti-pattern 2: Storing extractable key material in window/memory
  const importedKey = await crypto.subtle.importKey(
    'raw',
    rawSignature.slice(0, 32),
    { name: 'AES-GCM' },
    true, // CRITICAL: Extractable key material permits XSS exfiltration
    ['encrypt', 'decrypt']
  );

  // Anti-pattern 3: Storing raw key material in localStorage
  localStorage.setItem('encryptionKey', JSON.stringify(Array.from(rawSignature)));
  return importedKey;
}
```

#### Production Standard (Correct)
> **Standard**: Correctly invokes the WebAuthn Level 3 PRF extension with domain-separated salts. The resulting PRF output is ingested as an unextractable HKDF master key and derived into an unextractable AES-GCM 256-bit key handle. Crucially, the volatile intermediate PRF buffer is zeroized in a `finally` block to protect against heap scraping.
```typescript
export interface PrfDerivationParams {
  credentialId: Uint8Array;
  challenge: Uint8Array;
  domainSeparationSalt: Uint8Array;
  keyInfoContext: Uint8Array;
}

export async function deriveHardwareAnchoredKey({
  credentialId,
  challenge,
  domainSeparationSalt,
  keyInfoContext,
}: PrfDerivationParams): Promise<CryptoKey> {
  // 1. Invoke Authenticator with PRF extension and domain-separated salt
  const assertion = (await navigator.credentials.get({
    publicKey: {
      challenge,
      allowCredentials: [{ id: credentialId, type: 'public-key' }],
      userVerification: 'required',
      extensions: {
        prf: {
          eval: {
            first: domainSeparationSalt,
          },
        },
      },
    },
  })) as PublicKeyCredential | null;

  if (!assertion) {
    throw new Error('Authentication aborted or failed.');
  }

  const extensionResults = assertion.getClientExtensionResults();
  const prfResults = extensionResults.prf?.results;

  if (!prfResults?.first) {
    throw new Error('Authenticator does not support or grant PRF extension.');
  }

  const rawPrfBuffer = new Uint8Array(prfResults.first);

  try {
    // 2. Import raw PRF output as non-extractable HKDF master key
    const hkdfMasterKey = await crypto.subtle.importKey(
      'raw',
      rawPrfBuffer,
      { name: 'HKDF' },
      false, // CRITICAL: Never extractable
      ['deriveKey']
    );

    // 3. Derive targeted symmetric key (AES-GCM 256-bit) via HKDF expansion
    return await crypto.subtle.deriveKey(
      {
        name: 'HKDF',
        hash: 'SHA-256',
        salt: domainSeparationSalt,
        info: keyInfoContext,
      },
      hkdfMasterKey,
      { name: 'AES-GCM', length: 256 },
      false, // CRITICAL: Target key handle MUST remain non-extractable
      ['encrypt', 'decrypt']
    );
  } finally {
    // 4. Memory Hygiene: Explicitly zeroize raw hardware entropy buffer
    rawPrfBuffer.fill(0);
  }
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: WebAuthn Level 3 PRF Hardware-Anchored Symmetric Key Derivation Protocol

WebAuthn Level 3 PRF Hardware-Anchored Symmetric Key Derivation Protocol defines an industrial-grade behavioral standard for security engineering. Enforces strict cryptographic hygiene when using the WebAuthn Level 3 PRF (Pseudo-Random Function) extension for zero-knowledge client-side encryption. Requires non-extractable Web Crypto API key handles, domain-separated HKDF salt inputs, resilient extension capability checks, and explicit volatile memory zeroization to prevent key exfiltration via DOM XSS. 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: Deriving client encryption keys from authenticator signatures or retaining extractable raw PRF outputs in browser heap 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 DriftDeriving client encryption keys from authenticator signatures or retaining extractable raw PRF outputs in browser heapCritical
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 request the WebAuthn PRF extension via `extensions

Engineers MUST ALWAYS request the WebAuthn PRF extension via `extensions: { prf: { eval: { first: saltBuffer } } }` during `navigator.credentials.get` calls.

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 derive symmetric encryption keys from WebAuthn assertion signatures (`response.signature`), as signatures are verifiable by relying party servers and lack zero-knowledge confidentiality.

Engineers MUST NOT derive symmetric encryption keys from WebAuthn assertion signatures (`response.signature`), as signatures are verifiable by relying party servers and lack zero-knowledge confidentiality.

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 `clientExtensionResults.prf?.results?.first` exists and is an `ArrayBuffer` before attempting downstream cryptographic operations.

Code MUST verify `clientExtensionResults.prf?.results?.first` exists and is an `ArrayBuffer` before attempting downstream cryptographic operations.

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

Code MUST import the raw PRF entropy into `window.crypto.subtle.importKey` with `extractable

Code MUST import the raw PRF entropy into `window.crypto.subtle.importKey` with `extractable: false` and the `'HKDF'` algorithm immediately upon retrieval.

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

Code MUST zeroize the transient PRF `Uint8Array` buffer using `.fill(0)` immediately after importing into WebCrypto to minimize exposure window against browser memory dump attacks or prototype pollution / XSS.

Code MUST zeroize the transient PRF `Uint8Array` buffer using `.fill(0)` immediately after importing into WebCrypto to minimize exposure window against browser memory dump attacks or prototype pollution / XSS.

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 ALWAYS enforce domain separation by mixing a unique context string and user/account identifier into the PRF evaluation salt using HKDF or HMAC-SHA-256 before passing to the authenticator.

Engineers MUST ALWAYS enforce domain separation by mixing a unique context string and user/account identifier into the PRF evaluation salt using HKDF or HMAC-SHA-256 before passing to the authenticator.

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.
7

Components NEVER expose the raw derived key, intermediate PRF output, or base64 representations thereof to reactive UI state (e.g., Redux, Pinia, React state) or persistent web storage (localStorage, sessionStorage, IndexedDB).

Components NEVER expose the raw derived key, intermediate PRF output, or base64 representations thereof to reactive UI state (e.g., Redux, Pinia, React state) or persistent web storage (localStorage, sessionStorage, IndexedDB).

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 PRF Hardware-Anchored Symmetric Key Derivation Protocol critical for AI coding assistants?

Enforces strict cryptographic hygiene when using the WebAuthn Level 3 PRF (Pseudo-Random Function) extension for zero-knowledge client-side encryption. Requires non-extractable Web Crypto API key handles, domain-separated HKDF salt inputs, resilient extension capability checks, and explicit volatile memory zeroization to prevent key exfiltration via DOM XSS. 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 (Deriving client encryption keys from authenticator signatures or retaining extractable raw PRF outputs in browser heap) 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