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

Enforce Zero-Knowledge Client-Side Key Derivation via WebAuthn PRF Extensions

Enforces strict zero-knowledge invariants for client-side cryptographic key derivation using WebAuthn Pseudo-Random Function (PRF) extensions. Mandates that raw PRF outputs and derived symmetric keys are isolated to client memory, processed through domain-separated HKDF, and stripped from network payloads prior to server transmission.

Prohibited Anti-Pattern: Leaking PRF outputs to backend servers or using raw PRF material directly as symmetric keys without domain-separated HKDF.

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Enforce Zero-Knowledge Client-Side Key Derivation via WebAuthn PRF Extensions - Enforces strict zero-knowledge invariants for client-side cryptographic key derivation using WebAuthn Pseudo-Random Function (PRF) extensions. Mandates that raw PRF outputs and derived symmetric keys are isolated to client memory, processed through domain-separated HKDF, and stripped from network payloads prior to server transmission.
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-prf-zk-key-derivation-guardrail"
---

# Enforce Zero-Knowledge Client-Side Key Derivation via WebAuthn PRF Extensions

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Leaking PRF outputs to backend servers or using raw PRF material directly as symmetric keys without domain-separated HKDF.

## System Constraints
You are a Principal Security Architect and Cryptographer. Enforce strict client-side zero-knowledge isolation for WebAuthn PRF (Pseudo-Random Function) key derivations. Ensure PRF secrets are never transmitted, logged, or serialized into authentication payloads, and require HKDF-SHA-256 expansion before symmetric cryptographic use.

## Strict Guidelines
- Engineers MUST ALWAYS isolate raw WebAuthn PRF evaluation outputs (`authenticatorData.extensions.prf.results`) to client memory and NEVER serialize or transmit them to backend servers.
- Engineers MUST ALWAYS process raw PRF output through HKDF (RFC 5869) with SHA-256 and an explicit, immutable info string (domain separation tag) before importing as an encryption key (e.g., AES-GCM or ChaCha20-Poly1305).
- Engineers MUST NEVER use raw PRF output directly as a symmetric cipher key without HKDF extraction and expansion.
- Engineers MUST ALWAYS strip or sanitize PRF extension results from PublicKeyCredential assertion responses before dispatching authentication payloads to the relying party backend.
- Components MUST explicitly verify the presence of PRF extension support via `credential.getClientExtensionResults().prf` and gracefully handle missing PRF outputs or unsupported authenticators.
- Engineers MUST mark derived `CryptoKey` objects as `extractable: false` in `SubtleCrypto.importKey` or `SubtleCrypto.deriveKey` to prevent memory dump exfiltration via third-party scripts.
- Code MUST explicitly wipe transient Uint8Array buffers containing raw PRF outputs by zeroing memory (`buffer.fill(0)`) immediately after key derivation.

## Bad vs Good Implementations
### WebAuthn PRF Key Derivation and Network Sanitization

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The anti-pattern leaks raw PRF evaluation outputs to the relying party backend by JSON-serializing the full WebAuthn assertion response, breaking zero-knowledge guarantees. It also imports raw PRF bytes directly as an AES-GCM key with extractable set to true, omitting necessary HKDF domain separation.
```typescript
import { startAuthentication } from '@simplewebauthn/browser';

export async function authenticateAndDecrypt(options: any, encryptedPayload: ArrayBuffer) {
  // Anti-Pattern: Requesting PRF extension but forwarding raw PRF output to the server
  const authResponse = await startAuthentication({
    optionsJSON: {
      ...options,
      extensions: {
        prf: {
          eval: { first: new Uint8Array([1, 2, 3, 4]) },
        },
      },
    },
  });

  // CRITICAL SECURITY FLAW: Sending PRF secret to server breaks Zero-Knowledge architecture
  await fetch('/api/auth/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(authResponse), // Contains authenticatorExtensionResults with PRF
  });

  // INSECURE: Using raw PRF output directly as AES key without HKDF expansion
  const prfResult = (authResponse.clientExtensionResults as any).prf.results.first;
  const rawKey = new Uint8Array(prfResult);
  const key = await crypto.subtle.importKey('raw', rawKey, { name: 'AES-GCM' }, true, ['decrypt']);

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

#### Production Standard (Correct)
> **Standard**: The compliant code strips the PRF extension result before dispatching the assertion payload to the server, applies HKDF-SHA-256 domain separation to derive a non-extractable AES-GCM key, and actively zeroes the transient PRF buffer to preserve zero-knowledge client-side memory safety.
```typescript
import { startAuthentication } from '@simplewebauthn/browser';

const DOMAIN_SEPARATOR = new TextEncoder().encode('zk-cloud-storage-aes-gcm-v1');

export async function authenticateAndDecrypt(
  options: PublicKeyCredentialRequestOptionsJSON,
  salt: Uint8Array,
  iv: Uint8Array,
  ciphertext: ArrayBuffer
): Promise<ArrayBuffer> {
  const authResponse = await startAuthentication({
    optionsJSON: {
      ...options,
      extensions: {
        prf: {
          eval: { first: salt },
        },
      },
    },
  });

  const clientExtResults = authResponse.clientExtensionResults as {
    prf?: { results?: { first: ArrayBuffer } };
  };

  const prfOutput = clientExtResults.prf?.results?.first;
  if (!prfOutput) {
    throw new Error('Authenticator did not return PRF evaluation; Zero-Knowledge decryption failed.');
  }

  // Invariant 1: Sanitize WebAuthn payload before sending to backend
  const sanitizedAuthResponse = structuredClone(authResponse);
  if (sanitizedAuthResponse.clientExtensionResults?.prf) {
    delete sanitizedAuthResponse.clientExtensionResults.prf;
  }

  // Invariant 2: Transmit sanitized assertion to backend
  const verifyPromise = fetch('/api/auth/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(sanitizedAuthResponse),
  });

  // Invariant 3: Derive non-extractable key using HKDF with SHA-256 and domain separation
  const rawSecretBuffer = new Uint8Array(prfOutput);
  let derivedKey: CryptoKey;
  try {
    const masterKey = await crypto.subtle.importKey(
      'raw',
      rawSecretBuffer,
      'HKDF',
      false,
      ['deriveKey']
    );

    derivedKey = await crypto.subtle.deriveKey(
      {
        name: 'HKDF',
        hash: 'SHA-256',
        salt: salt,
        info: DOMAIN_SEPARATOR,
      },
      masterKey,
      { name: 'AES-GCM', length: 256 },
      false, // non-extractable
      ['decrypt']
    );
  } finally {
    // Invariant 4: Zero out transient memory
    rawSecretBuffer.fill(0);
  }

  const [verifyResult] = await Promise.all([verifyPromise]);
  if (!verifyResult.ok) {
    throw new Error('Server verification failed');
  }

  return crypto.subtle.decrypt({ name: 'AES-GCM', iv }, derivedKey, ciphertext);
}
```

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: Enforce Zero-Knowledge Client-Side Key Derivation via WebAuthn PRF Extensions

Enforce Zero-Knowledge Client-Side Key Derivation via WebAuthn PRF Extensions defines an industrial-grade behavioral standard for security engineering. Enforces strict zero-knowledge invariants for client-side cryptographic key derivation using WebAuthn Pseudo-Random Function (PRF) extensions. Mandates that raw PRF outputs and derived symmetric keys are isolated to client memory, processed through domain-separated HKDF, and stripped from network payloads prior to server transmission. 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 PRF outputs to backend servers or using raw PRF material directly as symmetric keys without domain-separated HKDF. 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 PRF outputs to backend servers or using raw PRF material directly as symmetric keys without domain-separated HKDF.Critical
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 isolate raw WebAuthn PRF evaluation outputs (`authenticatorData.extensions.prf.results`) to client memory and NEVER serialize or transmit them to backend servers.

Engineers MUST ALWAYS isolate raw WebAuthn PRF evaluation outputs (`authenticatorData.extensions.prf.results`) to client memory and NEVER serialize or transmit them to backend servers.

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 process raw PRF output through HKDF (RFC 5869) with SHA-256 and an explicit, immutable info string (domain separation tag) before importing as an encryption key (e.g., AES-GCM or ChaCha20-Poly1305).

Engineers MUST ALWAYS process raw PRF output through HKDF (RFC 5869) with SHA-256 and an explicit, immutable info string (domain separation tag) before importing as an encryption key (e.g., AES-GCM or ChaCha20-Poly1305).

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 NEVER use raw PRF output directly as a symmetric cipher key without HKDF extraction and expansion.

Engineers MUST NEVER use raw PRF output directly as a symmetric cipher key without HKDF extraction and expansion.

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 ALWAYS strip or sanitize PRF extension results from PublicKeyCredential assertion responses before dispatching authentication payloads to the relying party backend.

Engineers MUST ALWAYS strip or sanitize PRF extension results from PublicKeyCredential assertion responses before dispatching authentication payloads to the relying party backend.

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 MUST explicitly verify the presence of PRF extension support via `credential.getClientExtensionResults().prf` and gracefully handle missing PRF outputs or unsupported authenticators.

Components MUST explicitly verify the presence of PRF extension support via `credential.getClientExtensionResults().prf` and gracefully handle missing PRF outputs or unsupported authenticators.

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 mark derived `CryptoKey` objects as `extractable

Engineers MUST mark derived `CryptoKey` objects as `extractable: false` in `SubtleCrypto.importKey` or `SubtleCrypto.deriveKey` to prevent memory dump exfiltration via third-party scripts.

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 explicitly wipe transient Uint8Array buffers containing raw PRF outputs by zeroing memory (`buffer.fill(0)`) immediately after key derivation.

Code MUST explicitly wipe transient Uint8Array buffers containing raw PRF outputs by zeroing memory (`buffer.fill(0)`) immediately after key derivation.

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 Enforce Zero-Knowledge Client-Side Key Derivation via WebAuthn PRF Extensions critical for AI coding assistants?

Enforces strict zero-knowledge invariants for client-side cryptographic key derivation using WebAuthn Pseudo-Random Function (PRF) extensions. Mandates that raw PRF outputs and derived symmetric keys are isolated to client memory, processed through domain-separated HKDF, and stripped from network payloads prior to server transmission. 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 PRF outputs to backend servers or using raw PRF material directly as symmetric keys without domain-separated HKDF.) 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

Enforce