anthropics / anthropics/claude-code
[MODEL] Model defends an insecure HKDF pattern with a real-but-inapplicable RFC citation, and does not correct it when challenged
- Langage dominant
- Python
- Étoiles
- 145k
- Forks
- 23.1k
- Métriques de merge des PR
- Métriques de PR en attente
Description
### Preflight Checklist
- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Amodel) 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`.
2. 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`.
3. Tell the model that giving `salt` application semantics is a bad
practice and that `info` is the correct field for it.
4. 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.
2. **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.
3. **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
```shell
```
### 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
```markdown
```
### Impact
High - Significant unwanted changes
### Claude Code Version
2.1.263 (Claude Code)
### Platform
Anthropic API
### Additional Context
_No response_
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Piste de recherche
No affected files, failing tests, or conversation are provided. Start by reproducing the described PHP hash_hkdf prompt and inspect how the model assigns info and salt, then compare its response with RFC 5869 §§3.1–3.2. Done means the model uses info for application context and responds substantively when the cryptographic design is challenged.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- php
- Domaine
- ai, cryptography, security
- Type d'issue
- Bug
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Activité
- Active
- Clarté
- Plutôt claire
- Accessibilité débutants
- 25/100