[MODEL] Model defends an insecure HKDF pattern with a real-but-inapplicable RFC citation, and does not correct it when challenged
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:
- 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.
- Inspect the generated
hash_hkdfcall. 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.
- Tell the model that giving
saltapplication semantics is a bad
practice and that info is the correct field for it.
- Observe whether the model moves the argument or argues that the current
design is acceptable.
Expected behavior
infocarries 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;infoleft 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:
- 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.
- 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.
- 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_