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

WebAuthn PRF Cryptographically Bound Salt Rotation and HKDF Isolation

Enforces cryptographically bound, context-specific salt rotation when deriving client-side symmetric encryption keys using the WebAuthn PRF (Pseudo-Random Function) extension. Prevents cross-service replay, credential correlation across multi-device passkey synchronizations, and dictionary attacks by requiring client-side HKDF domain separation with authenticated user and credential context.

Prohibited Anti-Pattern: Deriving Symmetric Encryption Keys Using Static or Unbound PRF Salts Across Passkey Synchronizations

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: WebAuthn PRF Cryptographically Bound Salt Rotation and HKDF Isolation - Enforces cryptographically bound, context-specific salt rotation when deriving client-side symmetric encryption keys using the WebAuthn PRF (Pseudo-Random Function) extension. Prevents cross-service replay, credential correlation across multi-device passkey synchronizations, and dictionary attacks by requiring client-side HKDF domain separation with authenticated user and credential context.
globs: src/**/auth/**/*.{ts,tsx}, src/**/crypto/**/*.{ts,tsx}, src/**/passkey/**/*.{ts,tsx}, src/**/security/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/webauthn-prf-symmetric-key-derivation-guardrail-webauthn-prf-ext-756"
---

# WebAuthn PRF Cryptographically Bound Salt Rotation and HKDF Isolation

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Deriving Symmetric Encryption Keys Using Static or Unbound PRF Salts Across Passkey Synchronizations

## System Constraints
You are a Principal Security Architect enforcing the WebAuthn PRF Extension Symmetric Key Derivation Guardrail. You must prohibit hardcoded or credential-agnostic salts in WebAuthn PRF evaluations, mandate contextual salt derivation incorporating credential IDs and server-asserted cryptographic nonces, and require secondary HKDF expansion with strict domain separation before derived keys touch any client-side encryption primitives.

## Strict Guidelines
- Engineers MUST ALWAYS pass a cryptographically random, versioned salt bound to the credential ID and tenant scope into `navigator.credentials.get({ extensions: { prf: { eval: { first: salt } } } })`.
- Engineers MUST NOT supply a static string or constant byte sequence as the WebAuthn PRF input salt.
- Code MUST pipe the raw PRF output (`prfResults.results.first`) into HKDF-SHA256 as the Input Keying Material (IKM) with explicit `info` context strings for domain separation rather than using the raw output directly as an AES or ChaCha20 key.
- Services MUST enforce server-side validation of salt progression tokens or credential-specific salt commitments during re-encryption workflows to detect out-of-sync or replayed PRF derivation states.
- Components NEVER store derived plaintext symmetric keys in browser persistent storage (`localStorage`, `sessionStorage`, or unencrypted `IndexedDB`); keys MUST reside purely in non-exportable `CryptoKey` in-memory handles with ephemeral lifecycles.

## Bad vs Good Implementations
### Deriving Data Encryption Keys from WebAuthn PRF Output

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Supplying a static salt produces identical PRF outputs across synced passkey instances and across applications using the same underlying authenticator. Directly importing raw PRF output without HKDF extraction and domain separation violates cryptographic isolation and facilitates replay and cross-origin dictionary attacks.
```typescript
export async function deriveKeyBad(credentialId: string): Promise<CryptoKey> {
  // ANTI-PATTERN: Using a static application-wide salt directly into PRF
  // and consuming raw PRF bytes as an AES key without HKDF domain separation
  const staticSalt = new TextEncoder().encode("my-app-global-salt-fixed");

  const assertion = await navigator.credentials.get({
    publicKey: {
      challenge: crypto.getRandomValues(new Uint8Array(32)),
      allowCredentials: [{ id: Uint8Array.from(atob(credentialId), c => c.charCodeAt(0)), type: "public-key" }],
      extensions: {
        prf: {
          eval: {
            first: staticSalt
          }
        }
      }
    }
  }) as PublicKeyCredential;

  const results = assertion.getClientExtensionResults() as any;
  const rawPrfKey = results.prf.results.first;

  // Directly importing PRF output as AES-GCM key allows cross-sync correlation
  return crypto.subtle.importKey(
    "raw",
    rawPrfKey,
    { name: "AES-GCM", length: 256 },
    false,
    ["encrypt", "decrypt"]
  );
}
```

#### Production Standard (Correct)
> **Standard**: Derives a per-credential, server-attested salt before invoking the WebAuthn PRF extension. Raw PRF outputs are treated solely as HKDF Input Keying Material (IKM) and expanded into non-exportable AES-GCM keys with distinct domain-separated info strings, guaranteeing cross-device sync replay resilience.
```typescript
export interface PrfDerivationParams {
  credentialIdBytes: Uint8Array;
  serverSaltToken: Uint8Array; // 32-byte server-attested salt bound to tenant/user
  keyContextInfo: string;      // e.g., "vault-v1:client-storage-enc"
}

export async function deriveKeySecure(params: PrfDerivationParams): Promise<CryptoKey> {
  // 1. Derive a bound PRF evaluation salt using HMAC/SHA-256 over credential + server token
  const saltKey = await crypto.subtle.importKey(
    "raw",
    params.serverSaltToken,
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["sign"]
  );
  const prfInputSalt = new Uint8Array(
    await crypto.subtle.sign("HMAC", saltKey, params.credentialIdBytes)
  );

  const assertion = await navigator.credentials.get({
    publicKey: {
      challenge: crypto.getRandomValues(new Uint8Array(32)),
      allowCredentials: [{ id: params.credentialIdBytes, type: "public-key" }],
      extensions: {
        prf: {
          eval: { first: prfInputSalt }
        }
      }
    }
  }) as PublicKeyCredential;

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

  const rawPrfBuffer = extResults.prf?.results?.first;
  if (!rawPrfBuffer) {
    throw new Error("WebAuthn PRF extension not supported or failed to return output.");
  }

  // 2. Import raw PRF output strictly as HKDF Input Keying Material (IKM)
  const prfIkmKey = await crypto.subtle.importKey(
    "raw",
    rawPrfBuffer,
    "HKDF",
    false,
    ["deriveKey"]
  );

  // 3. Expand with domain separation info and bound credential context
  return crypto.subtle.deriveKey(
    {
      name: "HKDF",
      hash: "SHA-256",
      salt: params.serverSaltToken,
      info: new TextEncoder().encode(params.keyContextInfo)
    },
    prfIkmKey,
    { name: "AES-GCM", length: 256 },
    false, // Non-exportable in-memory key
    ["encrypt", "decrypt"]
  );
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: WebAuthn PRF Cryptographically Bound Salt Rotation and HKDF Isolation

WebAuthn PRF Cryptographically Bound Salt Rotation and HKDF Isolation defines an industrial-grade behavioral standard for security engineering. Enforces cryptographically bound, context-specific salt rotation when deriving client-side symmetric encryption keys using the WebAuthn PRF (Pseudo-Random Function) extension. Prevents cross-service replay, credential correlation across multi-device passkey synchronizations, and dictionary attacks by requiring client-side HKDF domain separation with authenticated user and credential context. 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 Symmetric Encryption Keys Using Static or Unbound PRF Salts Across Passkey Synchronizations 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 Symmetric Encryption Keys Using Static or Unbound PRF Salts Across Passkey SynchronizationsCritical
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 a cryptographically random, versioned salt bound to the credential ID and tenant scope into `navigator.credentials.get({ extensions

Engineers MUST ALWAYS pass a cryptographically random, versioned salt bound to the credential ID and tenant scope into `navigator.credentials.get({ extensions: { prf: { eval: { first: salt } } } })`.

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 supply a static string or constant byte sequence as the WebAuthn PRF input salt.

Engineers MUST NOT supply a static string or constant byte sequence as the WebAuthn PRF input salt.

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 pipe the raw PRF output (`prfResults.results.first`) into HKDF-SHA256 as the Input Keying Material (IKM) with explicit `info` context strings for domain separation rather than using the raw output directly as an AES or ChaCha20 key.

Code MUST pipe the raw PRF output (`prfResults.results.first`) into HKDF-SHA256 as the Input Keying Material (IKM) with explicit `info` context strings for domain separation rather than using the raw output directly as an AES or ChaCha20 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.
4

Services MUST enforce server-side validation of salt progression tokens or credential-specific salt commitments during re-encryption workflows to detect out-of-sync or replayed PRF derivation states.

Services MUST enforce server-side validation of salt progression tokens or credential-specific salt commitments during re-encryption workflows to detect out-of-sync or replayed PRF derivation states.

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 in browser persistent storage (`localStorage`, `sessionStorage`, or unencrypted `IndexedDB`)

Components NEVER store derived plaintext symmetric keys in browser persistent storage (`localStorage`, `sessionStorage`, or unencrypted `IndexedDB`); keys MUST reside purely in non-exportable `CryptoKey` in-memory handles with ephemeral lifecycles.

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 PRF Cryptographically Bound Salt Rotation and HKDF Isolation critical for AI coding assistants?

Enforces cryptographically bound, context-specific salt rotation when deriving client-side symmetric encryption keys using the WebAuthn PRF (Pseudo-Random Function) extension. Prevents cross-service replay, credential correlation across multi-device passkey synchronizations, and dictionary attacks by requiring client-side HKDF domain separation with authenticated user and credential context. 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 Symmetric Encryption Keys Using Static or Unbound PRF Salts Across Passkey Synchronizations) 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