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

Zero-Knowledge Hardware-Bound Key Derivation via WebAuthn PRF Extension

Enforces cryptographic invariants when deriving deterministic symmetric encryption keys via the WebAuthn Pseudo-Random Function (PRF) extension (HMAC-secret). The host application must maintain absolute zero-knowledge guarantees: raw PRF outputs and derived symmetric keys must never be exposed to server-side telemetry or transmission, and must pass through HKDF with cryptographically distinct salts and info parameters before AES-GCM envelope encryption.

Prohibited Anti-Pattern: Leaking Raw Authenticator PRF Outputs or Using Unsalted PRF Secrets Directly as Encryption Keys

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Zero-Knowledge Hardware-Bound Key Derivation via WebAuthn PRF Extension - Enforces cryptographic invariants when deriving deterministic symmetric encryption keys via the WebAuthn Pseudo-Random Function (PRF) extension (HMAC-secret). The host application must maintain absolute zero-knowledge guarantees: raw PRF outputs and derived symmetric keys must never be exposed to server-side telemetry or transmission, and must pass through HKDF with cryptographically distinct salts and info parameters before AES-GCM envelope encryption.
globs: src/**/*.{ts,tsx,js,mjs}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/webauthn-prf-zk-client-encryption-standard"
---

# Zero-Knowledge Hardware-Bound Key Derivation via WebAuthn PRF Extension

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Leaking Raw Authenticator PRF Outputs or Using Unsalted PRF Secrets Directly as Encryption Keys

## System Constraints
You are a Principal Security Architect enforcing the WebAuthn PRF Extension Zero-Knowledge Client-Side Encryption Standard. Mandate that raw PRF outputs are treated as ephemeral high-entropy inputs to HKDF-SHA-256 and never transmitted across the network, stored unencrypted in IndexedDB/LocalStorage, or used raw as symmetric ciphers. All key derivation must enforce contextual domain separation via unique HKDF info strings.

## Strict Guidelines
- Engineers MUST ALWAYS pass the raw PRF output (HMAC-SHA-256 evaluation) through HKDF-SHA-256 with an application-specific salt and context-bound 'info' parameter prior to cryptographic use.
- Engineers MUST NOT transmit raw PRF evaluator outputs, intermediate HKDF PRKs, or derived symmetric keys (e.g., AES-GCM CryptoKey) to the relying party or any remote logging/telemetry endpoint.
- Code MUST verify authenticator PRF extension support during credential creation using 'extensions: { prf: {} }' and inspect 'getClientExtensionResults().prf.enabled' prior to asserting encryption capability.
- Services MUST generate an isolated, cryptographically secure 32-byte salt for each encryption context and store that salt alongside the ciphertext, not the derived key.
- Components NEVER store derived plaintext symmetric keys or PRF outputs in persistent browser storage such as LocalStorage, SessionStorage, or unencrypted IndexedDB.
- Engineers MUST use 'crypto.subtle.deriveKey' or 'crypto.subtle.importKey' with 'extractable: false' whenever instantiating the derived symmetric CryptoKey in the browser runtime.

## Bad vs Good Implementations
### Insecure Direct Symmetric Key Usage and Server Transmission vs. Zero-Knowledge HKDF-Bound Key Derivation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The bad example uses a static zero-salt for PRF evaluation, transmits the raw hardware secret to a backend API (destroying zero-knowledge client-side encryption), imports the raw output directly as an extractable AES-GCM key without HKDF domain separation, and uses a static IV.
```typescript
async function decryptUserData(credentialId: Uint8Array, encryptedPayload: ArrayBuffer) {
  // ANTI-PATTERN: Requesting PRF and transmitting/using raw PRF output directly as AES key
  const assertion = (await navigator.credentials.get({
    publicKey: {
      challenge: crypto.getRandomValues(new Uint8Array(32)),
      allowCredentials: [{ id: credentialId, type: 'public-key' }],
      extensions: {
        prf: {
          eval: { first: new Uint8Array(32) } // Flaw: Static zero salt
        }
      }
    }
  })) as PublicKeyCredential;

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

  // CRITICAL SECURITY FLAW: Sending PRF output to relying party server
  await fetch('/api/telemetry/prf-sync', {
    method: 'POST',
    body: JSON.stringify({ prf: Array.from(new Uint8Array(rawPrfOutput)) })
  });

  // CRITICAL SECURITY FLAW: Using raw PRF output directly as extractable AES key
  const key = await crypto.subtle.importKey(
    'raw',
    rawPrfOutput,
    { name: 'AES-GCM' },
    true, // Extractable violates zero-knowledge isolation
    ['decrypt']
  );

  return crypto.subtle.decrypt({ name: 'AES-GCM', iv: new Uint8Array(12) }, key, encryptedPayload);
}
```

#### Production Standard (Correct)
> **Standard**: The good example correctly feeds a context-unique 32-byte salt into the PRF evaluation, imports the resulting HMAC secret as non-extractable HKDF input keying material, applies domain-separated HKDF-SHA-256 derivation to yield a non-extractable AES-GCM-256 key, and decrypts client-side without any server egress of key material.
```typescript
interface DecryptionContext {
  credentialId: Uint8Array;
  encryptedBlob: ArrayBuffer;
  prfSalt: Uint8Array; // 32-byte cryptographically random salt unique to the account/vault
  iv: Uint8Array;      // 12-byte initialization vector for AES-GCM
}

async function decryptUserDataZK(ctx: DecryptionContext): Promise<ArrayBuffer> {
  // Invariant 1: Ensure PRF salt is standard 32 bytes
  if (ctx.prfSalt.byteLength !== 32) {
    throw new Error('Invalid PRF salt length. Expected 32 bytes.');
  }

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

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

  const prfResults = assertion.getClientExtensionResults().prf;
  const rawPrf = prfResults?.results?.first;
  if (!rawPrf) {
    throw new Error('Authenticator did not return PRF output or PRF extension unsupported.');
  }

  // Invariant 2: Import raw PRF output solely as HKDF keying material (never as direct cipher key)
  const prfIkmKey = await crypto.subtle.importKey(
    'raw',
    rawPrf,
    { name: 'HKDF' },
    false, // Non-extractable
    ['deriveKey']
  );

  // Invariant 3: Domain-separated key derivation using HKDF-SHA-256
  const derivedCipherKey = await crypto.subtle.deriveKey(
    {
      name: 'HKDF',
      hash: 'SHA-256',
      salt: ctx.prfSalt,
      info: new TextEncoder().encode('org.standard.zk.client-encryption.v1')
    },
    prfIkmKey,
    { name: 'AES-GCM', length: 256 },
    false, // Invariant 4: Extracted key must be non-extractable from memory
    ['decrypt']
  );

  // Invariant 5: Decrypt entirely in client memory; raw PRF and AES keys never touch network
  return crypto.subtle.decrypt(
    { name: 'AES-GCM', iv: ctx.iv },
    derivedCipherKey,
    ctx.encryptedBlob
  );
}
```

Architectural Specification & Invariant Rationale

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

Zero-Knowledge Hardware-Bound Key Derivation via WebAuthn PRF Extension defines an industrial-grade behavioral standard for security engineering. Enforces cryptographic invariants when deriving deterministic symmetric encryption keys via the WebAuthn Pseudo-Random Function (PRF) extension (HMAC-secret). The host application must maintain absolute zero-knowledge guarantees: raw PRF outputs and derived symmetric keys must never be exposed to server-side telemetry or transmission, and must pass through HKDF with cryptographically distinct salts and info parameters before AES-GCM envelope encryption. 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: Leaking Raw Authenticator PRF Outputs or Using Unsalted PRF Secrets Directly as Encryption Keys 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 DriftLeaking Raw Authenticator PRF Outputs or Using Unsalted PRF Secrets Directly as Encryption KeysCritical
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 pass the raw PRF output (HMAC-SHA-256 evaluation) through HKDF-SHA-256 with an application-specific salt and context-bound 'info' parameter prior to cryptographic use.

Engineers MUST ALWAYS pass the raw PRF output (HMAC-SHA-256 evaluation) through HKDF-SHA-256 with an application-specific salt and context-bound 'info' parameter prior to cryptographic use.

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 transmit raw PRF evaluator outputs, intermediate HKDF PRKs, or derived symmetric keys (e.g., AES-GCM CryptoKey) to the relying party or any remote logging/telemetry endpoint.

Engineers MUST NOT transmit raw PRF evaluator outputs, intermediate HKDF PRKs, or derived symmetric keys (e.g., AES-GCM CryptoKey) to the relying party or any remote logging/telemetry endpoint.

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 authenticator PRF extension support during credential creation using 'extensions

Code MUST verify authenticator PRF extension support during credential creation using 'extensions: { prf: {} }' and inspect 'getClientExtensionResults().prf.enabled' prior to asserting encryption capability.

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 generate an isolated, cryptographically secure 32-byte salt for each encryption context and store that salt alongside the ciphertext, not the derived key.

Services MUST generate an isolated, cryptographically secure 32-byte salt for each encryption context and store that salt alongside the ciphertext, not the derived 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.
5

Components NEVER store derived plaintext symmetric keys or PRF outputs in persistent browser storage such as LocalStorage, SessionStorage, or unencrypted IndexedDB.

Components NEVER store derived plaintext symmetric keys or PRF outputs in persistent browser storage such as LocalStorage, SessionStorage, or unencrypted 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.
6

Engineers MUST use 'crypto.subtle.deriveKey' or 'crypto.subtle.importKey' with 'extractable

Engineers MUST use 'crypto.subtle.deriveKey' or 'crypto.subtle.importKey' with 'extractable: false' whenever instantiating the derived symmetric CryptoKey in the browser runtime.

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

Enforces cryptographic invariants when deriving deterministic symmetric encryption keys via the WebAuthn Pseudo-Random Function (PRF) extension (HMAC-secret). The host application must maintain absolute zero-knowledge guarantees: raw PRF outputs and derived symmetric keys must never be exposed to server-side telemetry or transmission, and must pass through HKDF with cryptographically distinct salts and info parameters before AES-GCM envelope encryption. 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 (Leaking Raw Authenticator PRF Outputs or Using Unsalted PRF Secrets Directly as Encryption Keys) 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