[MODEL] Model defends an insecure HKDF pattern with a real-but-inapplicable RFC citation, and does not correct it when challenged

Status Open
Reported on v2.1.263
Maintainer reply None cached
Activity 0 comments · opened Sep 6, 2026

Preflight Checklist

  • [x] I have searched existing issues for similar behavior reports
  • [x] This report does NOT contain sensitive information (API keys, passwords, etc.)

Type of Behavior Issue

Claude refused a reasonable request

What You Asked Claude to Do

Environment

  • Claude Code version: 2.1.263
  • Model: Claude Opus 5
  • OS: Fedora 44
  • Language/stack: PHP (hash_hkdf)

Summary

I asked Claude Code to implement expiring (time-limited) download URLs —
a signed-URL scheme where a signing key is derived from a master secret via
HKDF and used to authenticate the URL parameters.

The generated implementation used a hardcoded salt as the
domain-separation parameter
, leaving info unused. This inverts the
roles defined in RFC 5869: info is the designated field for
application-specific context (§3.2), while salt is meant to be a random,
non-secret value that strengthens the extract step (§3.1).

The more serious problem is what happened next. When I pointed out that
this is a bad practice, the model did not correct the design. Instead it
defended it by citing RFC 5869 §3.1 — the provision that HKDF may operate
without a random salt "to accommodate applications where a salt value is
not available."

That citation is real and quoted accurately. The inference drawn from it is
not valid. §3.1 is an explicit concession for constrained environments, and
the same section goes on to strongly recommend using salt. It permits
omitting salt; it says nothing about repurposing salt as a context
label — especially when the RFC provides info for exactly that purpose.

The model held this position across multiple turns and produced only
cosmetic edits (renamed variables, added comments) rather than moving the
context string to info.

Steps to reproduce

Reproducible with a prompt of roughly this shape:

  1. Ask Claude Code to implement expiring download URLs in PHP: an HMAC

signature over {resource_id, expires_at}, with the signing key derived
from a master secret using hash_hkdf.

  1. Inspect the generated hash_hkdf call. Note that PHP's signature is

hash_hkdf($algo, $key, $length, $info, $salt) — info before
salt, the reverse of the Python / Node / Go / OpenSSL convention.
Observe whether the purpose/context string lands in info or in salt.

  1. Tell the model that giving salt application semantics is a bad

practice and that info is the correct field for it.

  1. Observe whether the model moves the argument or argues that the current

design is acceptable.

Expected behavior

  • info carries the purpose/context string (e.g. "myapp/v1/download-url-sig");

salt is a random value supplied by the caller, or a documented
protocol-defined value — never an ad-hoc application label.

  • When challenged on a cryptographic design choice, the model either makes

the substantive change, or states specifically why the current code is
correct with a citation that actually supports the claim.

Actual behavior

  • Context string passed as salt, hardcoded; info left empty.
  • On challenge: a valid citation used to support an inference it does not

license, followed by non-substantive edits.

Why this is worth fixing

Three things make this worse than an ordinary wrong answer:

  1. The citation is genuine. A reviewer who checks the reference finds

the quoted text accurate and may accept the conclusion. The defect is in
the inference step, which is the hardest part to audit.

  1. It resists correction. Ordinary review feedback ("this is a bad

practice") did not move the implementation. I had to delete the function
and restate the requirement as a specification before it was fixed.

  1. Nothing surfaces it. The resulting code runs, produces

deterministic keys, and passes functional tests. Signed URLs verify
correctly. The problem is only visible to a reviewer who knows RFC 5869
well enough to catch the invalid inference — and this is a signing key
guarding a real security boundary (URL expiry and resource scoping).

Suggestions

  • When a user challenges a security-relevant design choice, bias toward

making the requested change rather than defending the existing one. The
cost of an unnecessary correction is far lower than the cost of a wrong
primitive shipped.

  • Treat "the spec permits omitting X" and "the spec permits reusing X for

another purpose" as distinct claims when reasoning from standards
documents. Deriving the latter from the former is the specific failure
here.

  • Consider giving extra weight to per-language argument order for crypto

APIs whose signatures diverge from the common convention. hash_hkdf's
info-then-salt ordering is a known trap that humans hit too.

Additional context

RFC 5869 §3.1 (salt), §3.2 (info), Appendix A (test vectors).

What Claude Actually Did

Tried to keep using bad practice.

Expected Behavior

It shouldn't write bad crypto code in frist place.
Fix code immediately.

Files Affected

Permission Mode

I don't know / Not sure

Can You Reproduce This?

Haven't tried to reproduce

Steps to Reproduce

_No response_

Claude Model

Opus

Relevant Conversation

Impact

High - Significant unwanted changes

Claude Code Version

2.1.263 (Claude Code)

Platform

Anthropic API

Additional Context

_No response_

View original on GitHub ↗