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

Zero-Knowledge Hardware Key Derivation via WebAuthn PRF Extension

Enforces cryptographic and memory-safety invariants for client-side encryption key derivation using the WebAuthn PRF (Pseudo-Random Function) extension. Ensures authenticators derive zero-knowledge symmetric keys without persisting raw seeds, PRF outputs, or master keys to client storage, and mandates HKDF-SHA256 expansion with domain separation.

Prohibited Anti-Pattern: Persisting Derived PRF Secrets in Web Storage or Using Raw PRF Outputs Directly Without HKDF Domain Separation

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Zero-Knowledge Hardware Key Derivation via WebAuthn PRF Extension - Enforces cryptographic and memory-safety invariants for client-side encryption key derivation using the WebAuthn PRF (Pseudo-Random Function) extension. Ensures authenticators derive zero-knowledge symmetric keys without persisting raw seeds, PRF outputs, or master keys to client storage, and mandates HKDF-SHA256 expansion with domain separation.
globs: src/**/*.{ts,tsx}, lib/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/webauthn-prf-zk-key-derivation-security"
---

# Zero-Knowledge Hardware Key Derivation via WebAuthn PRF Extension

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Persisting Derived PRF Secrets in Web Storage or Using Raw PRF Outputs Directly Without HKDF Domain Separation

## System Constraints
You are a Principal Security Architect enforcing zero-knowledge client-side encryption via WebAuthn PRF (RFC 8288 / FIDO PRF Extension). You must mandate that client master secrets never exist in persistent storage (localStorage, sessionStorage, IndexedDB, cookies, or remote databases), derived PRF outputs are treated as ephemeral high-entropy seed material expanded strictly via HKDF with strict domain separation, and derived WebCrypto CryptoKey instances are marked non-extractable.

## Strict Guidelines
- Engineers MUST ALWAYS verify authenticator PRF extension support via `PublicKeyCredential.isConditionalMediationAvailable()` and checking `credential.getClientExtensionResults().prf` return values before proceeding.
- Engineers MUST NEVER persist raw PRF evaluation outputs, derived Key Encryption Keys (KEK), or Data Encryption Keys (DEK) in persistent storage (IndexedDB, localStorage, sessionStorage, cookies) or send them over network requests.
- Engineers MUST ALWAYS expand the raw 32-byte PRF output using HKDF-SHA256 (via WebCrypto `deriveKey` with an application-specific `info` string and distinct salt) before initializing symmetric ciphers like AES-GCM.
- Engineers MUST instantiate derived `CryptoKey` instances with `extractable: false` to prevent memory scraping and DOM extraction attacks.
- Code SHOULD zero out ephemeral TypedArrays (e.g., `buffer.fill(0)`) containing raw PRF results immediately after importing or deriving subsequent keys.
- Services MUST reject unauthenticated fallbacks: if an authenticator does not support the PRF extension, the client MUST NOT silently substitute a static, weak, or server-controlled fallback key.

## Bad vs Good Implementations
### Insecure PRF Key Extraction and Persistence vs. Ephemeral Non-Extractable HKDF Expansion

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Directly using the raw PRF output as an AES-GCM key risks cryptographic bias and lacks domain separation. Persisting the hex-encoded PRF output to `localStorage` permanently breaks the zero-knowledge invariant, allowing any client-side script or XSS payload to recover the master key.
```typescript
export async function unlockUserVaultInsecure(credentialId: Uint8Array): Promise<CryptoKey> {
  const credential = await navigator.credentials.get({
    publicKey: {
      challenge: crypto.getRandomValues(new Uint8Array(32)),
      allowCredentials: [{ id: credentialId, type: 'public-key' }],
      extensions: {
        prf: {
          eval: { first: new TextEncoder().encode('vault-salt') },
        },
      },
    },
  }) as PublicKeyCredential;

  const prfResult = credential.getClientExtensionResults().prf?.results?.first;
  if (!prfResult) {
    throw new Error('PRF failed, using fallback static key');
  }

  // CRITICAL SECURITY VIOLATIONS:
  // 1. Raw PRF output used directly as AES key without HKDF expansion.
  // 2. Extracted and stored in localStorage (breaks zero-knowledge invariant).
  // 3. Marked extractable: true allowing exfiltration via XSS.
  const hexSecret = Array.from(new Uint8Array(prfResult))
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('');
  localStorage.setItem('master_key', hexSecret);

  return crypto.subtle.importKey(
    'raw',
    prfResult,
    { name: 'AES-GCM', length: 256 },
    true,
    ['encrypt', 'decrypt']
  );
}
```

#### Production Standard (Correct)
> **Standard**: Validates authenticator PRF response, imports the raw output solely as non-extractable HKDF key material, immediately zeroes the temporary buffer, applies HKDF-SHA256 with domain-separated info parameters, and outputs a non-extractable CryptoKey never written to persistent storage.
```typescript
export async function deriveVaultKeyWithPRF(
  credentialId: Uint8Array,
  salt: Uint8Array,
  domainContext: string
): Promise<CryptoKey> {
  const credential = await navigator.credentials.get({
    publicKey: {
      challenge: crypto.getRandomValues(new Uint8Array(32)),
      allowCredentials: [{ id: credentialId, type: 'public-key' }],
      extensions: {
        prf: {
          eval: { first: salt },
        },
      },
    },
  }) as PublicKeyCredential | null;

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

  const extensionResults = credential.getClientExtensionResults();
  const rawPrfBuffer = extensionResults.prf?.results?.first;

  if (!rawPrfBuffer) {
    throw new Error('Authenticator does not support WebAuthn PRF extension.');
  }

  // Import raw PRF output as ephemeral HKDF Key Material (non-extractable)
  const prfKeyMaterial = await crypto.subtle.importKey(
    'raw',
    rawPrfBuffer,
    { name: 'HKDF' },
    false,
    ['deriveKey']
  );

  // Securely overwrite the raw PRF buffer in memory immediately
  new Uint8Array(rawPrfBuffer).fill(0);

  // Derive non-extractable AES-GCM Key with explicit context and info parameter
  const derivedKey = await crypto.subtle.deriveKey(
    {
      name: 'HKDF',
      hash: 'SHA-256',
      salt: salt,
      info: new TextEncoder().encode(`zk-vault-domain:${domainContext}`),
    },
    prfKeyMaterial,
    { name: 'AES-GCM', length: 256 },
    false, // Invariant: extractable must be false
    ['encrypt', 'decrypt']
  );

  return derivedKey;
}
```

Recommended MCP Servers (mcp-serverlist.com)

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

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Zero-Knowledge Hardware Key Derivation via WebAuthn PRF Extension

Zero-Knowledge Hardware Key Derivation via WebAuthn PRF Extension defines an industrial-grade behavioral standard for security engineering. Enforces cryptographic and memory-safety invariants for client-side encryption key derivation using the WebAuthn PRF (Pseudo-Random Function) extension. Ensures authenticators derive zero-knowledge symmetric keys without persisting raw seeds, PRF outputs, or master keys to client storage, and mandates HKDF-SHA256 expansion with domain separation. 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 Derived PRF Secrets in Web Storage or Using Raw PRF Outputs Directly Without HKDF Domain Separation 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 Derived PRF Secrets in Web Storage or Using Raw PRF Outputs Directly Without HKDF Domain SeparationCritical
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 authenticator PRF extension support via `PublicKeyCredential.isConditionalMediationAvailable()` and checking `credential.getClientExtensionResults().prf` return values before proceeding.

Engineers MUST ALWAYS verify authenticator PRF extension support via `PublicKeyCredential.isConditionalMediationAvailable()` and checking `credential.getClientExtensionResults().prf` return values before proceeding.

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 NEVER persist raw PRF evaluation outputs, derived Key Encryption Keys (KEK), or Data Encryption Keys (DEK) in persistent storage (IndexedDB, localStorage, sessionStorage, cookies) or send them over network requests.

Engineers MUST NEVER persist raw PRF evaluation outputs, derived Key Encryption Keys (KEK), or Data Encryption Keys (DEK) in persistent storage (IndexedDB, localStorage, sessionStorage, cookies) or send them over network requests.

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 expand the raw 32-byte PRF output using HKDF-SHA256 (via WebCrypto `deriveKey` with an application-specific `info` string and distinct salt) before initializing symmetric ciphers like AES-GCM.

Engineers MUST ALWAYS expand the raw 32-byte PRF output using HKDF-SHA256 (via WebCrypto `deriveKey` with an application-specific `info` string and distinct salt) before initializing symmetric ciphers like AES-GCM.

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 instantiate derived `CryptoKey` instances with `extractable

Engineers MUST instantiate derived `CryptoKey` instances with `extractable: false` to prevent memory scraping and DOM extraction 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.
5

Code SHOULD zero out ephemeral TypedArrays (e.g., `buffer.fill(0)`) containing raw PRF results immediately after importing or deriving subsequent keys.

Code SHOULD zero out ephemeral TypedArrays (e.g., `buffer.fill(0)`) containing raw PRF results immediately after importing or deriving subsequent keys.

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 reject unauthenticated fallbacks

Services MUST reject unauthenticated fallbacks: if an authenticator does not support the PRF extension, the client MUST NOT silently substitute a static, weak, or server-controlled fallback key.

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 Zero-Knowledge Hardware Key Derivation via WebAuthn PRF Extension critical for AI coding assistants?

Enforces cryptographic and memory-safety invariants for client-side encryption key derivation using the WebAuthn PRF (Pseudo-Random Function) extension. Ensures authenticators derive zero-knowledge symmetric keys without persisting raw seeds, PRF outputs, or master keys to client storage, and mandates HKDF-SHA256 expansion with domain separation. 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 Derived PRF Secrets in Web Storage or Using Raw PRF Outputs Directly Without HKDF Domain Separation) 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

Zero-Knowledge