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

WebAuthn Level 3 PRF Zero-Knowledge Key Derivation and Lifecycle Invariant

Enforces deterministic, zero-knowledge symmetric key derivation using the WebAuthn Level 3 PRF (Pseudo-Random Function) extension. Derived raw secret material MUST be processed via HKDF with domain-separated contexts, marked non-extractable, zeroized in volatile memory, and NEVER transmitted across network boundaries or stored in persistent client-side storage.

Prohibited Anti-Pattern: Persisting raw PRF outputs or treating PRF output as directly usable symmetric keys without HKDF expansion and extractability guards

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: WebAuthn Level 3 PRF Zero-Knowledge Key Derivation and Lifecycle Invariant - Enforces deterministic, zero-knowledge symmetric key derivation using the WebAuthn Level 3 PRF (Pseudo-Random Function) extension. Derived raw secret material MUST be processed via HKDF with domain-separated contexts, marked non-extractable, zeroized in volatile memory, and NEVER transmitted across network boundaries or stored in persistent client-side storage.
globs: src/**/*.{ts,tsx}, lib/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/webauthn-l3-prf-zero-knowledge-key-derivation-standard"
---

# WebAuthn Level 3 PRF Zero-Knowledge Key Derivation and Lifecycle Invariant

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Persisting raw PRF outputs or treating PRF output as directly usable symmetric keys without HKDF expansion and extractability guards

## System Constraints
You are a Principal Security Architect enforcing the WebAuthn Level 3 PRF (Pseudo-Random Function) Zero-Knowledge Standard. Ensure all key derivation logic uses WebCrypto HKDF-SHA-256 for domain separation, mandates 32-byte cryptographically secure salts, enforces non-extractable CryptoKey policies, strictly prohibits sending derived master keys to servers or unencrypted persistent storage, and guarantees the zeroization of ephemeral memory buffers.

## Strict Guidelines
- Engineers MUST ALWAYS feed raw PRF output (`results.prf.results.first`) into WebCrypto HKDF (HMAC-based Extract-and-Expand Key Derivation Function) using SHA-256 and an explicit, domain-separated `info` parameter before using it for encryption.
- Engineers MUST ALWAYS enforce `extractable: false` when importing or deriving symmetric operational keys (e.g., AES-GCM) via `crypto.subtle.deriveKey`.
- Engineers MUST ALWAYS explicitly zeroize ephemeral Uint8Array buffers containing raw PRF entropy immediately after deriving the operational key using `buffer.fill(0)`.
- Engineers MUST NOT persist raw PRF output, intermediate HKDF entropy, or derived symmetric keys in `localStorage`, `sessionStorage`, `IndexedDB`, or cookies under any circumstances.
- Engineers MUST NOT transmit raw PRF output or derived master encryption keys over the network or expose them to backend verification endpoints.
- Code SHOULD verify hardware authenticator PRF support via `clientExtensionResults.prf?.enabled` or check for existence of `results.first` before attempting derivation, providing explicit recovery workflows if PRF is unsupported.
- Code MUST require salt inputs for PRF evaluation to be exactly 32 bytes generated via `crypto.getRandomValues(new Uint8Array(32))` and stored publicly alongside encrypted payloads.
- Components NEVER store or expose non-extractable `CryptoKey` references on global window scopes or debug consoles.

## Bad vs Good Implementations
### WebAuthn PRF Key Derivation and Non-Extractable CryptoKey Instantiation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Directly casts raw PRF output into an AES key without HKDF expansion/domain separation, marks the key as extractable, stores raw key material in persistent client storage (localStorage), sends the raw key to a remote server (destroying zero-knowledge guarantees), and fails to zeroize raw cryptographic buffers.
```typescript
import { get } from '@github/webauthn-json';

export async function deriveKeyAndSave(credentialId: string, salt: string) {
  const credential = await navigator.credentials.get({
    publicKey: {
      challenge: new Uint8Array(32),
      allowCredentials: [{ id: new TextEncoder().encode(credentialId), type: 'public-key' }],
      extensions: {
        // @ts-expect-error prF extension typing
        prf: { eval: { first: new TextEncoder().encode(salt) } }
      }
    }
  }) as PublicKeyCredential;

  const extensionResults = credential.getClientExtensionResults() as any;
  const rawKey = extensionResults.prf.results.first;

  // CRITICAL ANTI-PATTERNS:
  // 1. Using raw PRF output directly as AES key without HKDF domain separation
  // 2. Setting extractable: true
  // 3. Storing raw key material in localStorage
  // 4. Leaking derived key over network
  const key = await crypto.subtle.importKey(
    'raw',
    rawKey,
    { name: 'AES-GCM' },
    true,
    ['encrypt', 'decrypt']
  );

  localStorage.setItem('encryption_key', JSON.stringify(Array.from(new Uint8Array(rawKey))));
  await fetch('/api/backup-key', { method: 'POST', body: JSON.stringify({ key: Array.from(new Uint8Array(rawKey)) }) });

  return key;
}
```

#### Production Standard (Correct)
> **Standard**: Validates the 32-byte salt constraint, extracts the PRF raw entropy, binds it to an HKDF-SHA-256 derivation with an explicit domain-separated `info` parameter, generates a non-extractable 256-bit AES-GCM key, zeroizes intermediate memory using `fill(0)` within a `finally` block, and never exports or transmits raw key material.
```typescript
export interface DerivedCipherContext {
  encryptionKey: CryptoKey;
}

export async function deriveZeroKnowledgeKey(
  credentialId: Uint8Array,
  prfSalt32Bytes: Uint8Array,
  purpose: string
): Promise<DerivedCipherContext> {
  if (prfSalt32Bytes.byteLength !== 32) {
    throw new Error('PRF Salt must be exactly 32 bytes.');
  }

  const assertion = await navigator.credentials.get({
    publicKey: {
      challenge: crypto.getRandomValues(new Uint8Array(32)),
      allowCredentials: [{ id: credentialId, type: 'public-key' }],
      userVerification: 'required',
      extensions: {
        prf: {
          eval: {
            first: prfSalt32Bytes
          }
        }
      }
    }
  }) as PublicKeyCredential | null;

  if (!assertion) {
    throw new Error('WebAuthn assertion failed or cancelled.');
  }

  const extensionResults = assertion.getClientExtensionResults() as AuthenticationExtensionsClientOutputs & {
    prf?: { results?: { first: ArrayBuffer } };
  };

  const rawPrfOutput = extensionResults.prf?.results?.first;
  if (!rawPrfOutput) {
    throw new Error('Authenticator does not support WebAuthn PRF extension.');
  }

  const prfBuffer = new Uint8Array(rawPrfOutput);

  try {
    // 1. Import raw PRF output as HKDF Master Key
    const hkdfMaster = await crypto.subtle.importKey(
      'raw',
      prfBuffer,
      'HKDF',
      false,
      ['deriveKey']
    );

    // 2. Derive non-extractable operational AES-GCM key with domain separation context
    const encryptionKey = await crypto.subtle.deriveKey(
      {
        name: 'HKDF',
        hash: 'SHA-256',
        salt: prfSalt32Bytes,
        info: new TextEncoder().encode(`webauthn-prf-v1:${purpose}`)
      },
      hkdfMaster,
      { name: 'AES-GCM', length: 256 },
      false, // non-extractable: cannot be exported or leaked via XSS
      ['encrypt', 'decrypt']
    );

    return { encryptionKey };
  } finally {
    // 3. Guaranteed zeroization of intermediate plaintext buffer in volatile memory
    prfBuffer.fill(0);
  }
}
```

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 PRF Zero-Knowledge Key Derivation and Lifecycle Invariant

WebAuthn Level 3 PRF Zero-Knowledge Key Derivation and Lifecycle Invariant defines an industrial-grade behavioral standard for security engineering. Enforces deterministic, zero-knowledge symmetric key derivation using the WebAuthn Level 3 PRF (Pseudo-Random Function) extension. Derived raw secret material MUST be processed via HKDF with domain-separated contexts, marked non-extractable, zeroized in volatile memory, and NEVER transmitted across network boundaries or stored in persistent client-side storage. 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 raw PRF outputs or treating PRF output as directly usable symmetric keys without HKDF expansion and extractability guards 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 raw PRF outputs or treating PRF output as directly usable symmetric keys without HKDF expansion and extractability guardsCritical
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 feed raw PRF output (`results.prf.results.first`) into WebCrypto HKDF (HMAC-based Extract-and-Expand Key Derivation Function) using SHA-256 and an explicit, domain-separated `info` parameter before using it for encryption.

Engineers MUST ALWAYS feed raw PRF output (`results.prf.results.first`) into WebCrypto HKDF (HMAC-based Extract-and-Expand Key Derivation Function) using SHA-256 and an explicit, domain-separated `info` parameter before using it for encryption.

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 enforce `extractable

Engineers MUST ALWAYS enforce `extractable: false` when importing or deriving symmetric operational keys (e.g., AES-GCM) via `crypto.subtle.deriveKey`.

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 explicitly zeroize ephemeral Uint8Array buffers containing raw PRF entropy immediately after deriving the operational key using `buffer.fill(0)`.

Engineers MUST ALWAYS explicitly zeroize ephemeral Uint8Array buffers containing raw PRF entropy immediately after deriving the operational key using `buffer.fill(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.
4

Engineers MUST NOT persist raw PRF output, intermediate HKDF entropy, or derived symmetric keys in `localStorage`, `sessionStorage`, `IndexedDB`, or cookies under any circumstances.

Engineers MUST NOT persist raw PRF output, intermediate HKDF entropy, or derived symmetric keys in `localStorage`, `sessionStorage`, `IndexedDB`, or cookies under any circumstances.

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

Engineers MUST NOT transmit raw PRF output or derived master encryption keys over the network or expose them to backend verification endpoints.

Engineers MUST NOT transmit raw PRF output or derived master encryption keys over the network or expose them to backend verification endpoints.

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

Code SHOULD verify hardware authenticator PRF support via `clientExtensionResults.prf?.enabled` or check for existence of `results.first` before attempting derivation, providing explicit recovery workflows if PRF is unsupported.

Code SHOULD verify hardware authenticator PRF support via `clientExtensionResults.prf?.enabled` or check for existence of `results.first` before attempting derivation, providing explicit recovery workflows if PRF is unsupported.

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

Code MUST require salt inputs for PRF evaluation to be exactly 32 bytes generated via `crypto.getRandomValues(new Uint8Array(32))` and stored publicly alongside encrypted payloads.

Code MUST require salt inputs for PRF evaluation to be exactly 32 bytes generated via `crypto.getRandomValues(new Uint8Array(32))` and stored publicly alongside encrypted payloads.

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

Components NEVER store or expose non-extractable `CryptoKey` references on global window scopes or debug consoles.

Components NEVER store or expose non-extractable `CryptoKey` references on global window scopes or debug consoles.

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 Zero-Knowledge Key Derivation and Lifecycle Invariant critical for AI coding assistants?

Enforces deterministic, zero-knowledge symmetric key derivation using the WebAuthn Level 3 PRF (Pseudo-Random Function) extension. Derived raw secret material MUST be processed via HKDF with domain-separated contexts, marked non-extractable, zeroized in volatile memory, and NEVER transmitted across network boundaries or stored in persistent client-side storage. 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 raw PRF outputs or treating PRF output as directly usable symmetric keys without HKDF expansion and extractability guards) 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