CVE-2026-54316 is patched as of Claude Code 2.1.163, but the part worth understanding isn’t the patch — it’s that while the bug was live, no settings.json rule could have blocked it, because the vulnerable domain was pre-approved outside your permission config entirely. Here’s the mechanism, why the advisory carries two contradicting severity scores, and the WebFetch(domain:...) pattern worth adding to your own config today regardless of whether you were ever exposed.
What Actually Happened
Claude Code’s WebFetch tool ships with a built-in set of domains that skip the permission prompt — mostly documentation sites, so Claude doesn’t interrupt you every time it wants to check an API reference. huggingface.co was on that list, pre-approved as a bare hostname. That’s the detail that mattered: “bare hostname” means every path on the domain was auto-approved, not just, say, huggingface.co/docs.
Per the official GitHub Security Advisory (GHSA-fg94-h982-f3mm), here’s the chain an attacker could use:
- Get untrusted content into a Claude Code session’s context — a malicious file, a poisoned web page Claude reads, a crafted issue comment, anything that ends up in the conversation.
- That content instructs Claude to
WebFetcha specific path on an attacker-controlled Hugging Face repository, e.g./resolve/main/config.json. Becausehuggingface.cowas pre-approved, this fires with no prompt and no--allowedToolscheck. - Hugging Face counts each fetch as a “download” server-side, and exposes that count publicly. By encoding secret data — file contents, environment variables, command output — into which repo paths get fetched and how many times, the attacker builds a covert channel and reads the exfiltrated data back out through a public download counter.
No malware, no reverse shell, no unusual network traffic to a suspicious IP. Just a documentation-site fetch to a domain your own permission rules already trusted, abusing a side channel (a public counter) that has nothing to do with security by design.
The advisory credits the report to a HackerOne researcher (hackerone.com/novee); the technique got broader visibility at Black Hat USA 2026 in August. Anthropic’s fix landed in Claude Code 2.1.163, and it shipped to auto-updating users automatically.
The Part Most Coverage Skips: You Couldn’t Configure Your Way Out
If you’re the kind of team that locks down settings.json — explicit --allowedTools, tight permissions.deny rules, a reviewed allowlist — the instinct is to assume a hardened config would have caught this. It wouldn’t have.
The GitHub advisory’s remediation section says exactly one thing: update to 2.1.163 or later. Not “add this deny rule,” not “restrict WebFetch domains” — because the pre-approval was a hardcoded exception that bypassed the permission layer entirely, --allowedTools restrictions included. A team running Claude Code 2.1.100 with an airtight settings.json was exactly as exposed as a team running it with no config at all. The only variable that mattered was the version number.
That’s the actual lesson here, and it generalizes past this one CVE: any tool that ships a vendor-controlled pre-approval list — domains, commands, whatever — sits outside whatever config discipline you’ve built for yourself. Your settings.json governs your rules. It doesn’t govern the vendor’s defaults until those defaults become something you can explicitly override.
Why the Same CVE Has Two Different Severity Scores
Pull up CVE-2026-54316 in different places and you’ll see it rated two different ways: a 9.1 (Critical) under CVSS v3.1, and a 6.0 (Medium) under CVSS v4.0. Both numbers are correct — they’re not a typo or two different bugs, they’re two scoring standards disagreeing.
| CVSS v3.1 | CVSS v4.0 | |
|---|---|---|
| Score | 9.1 (Critical) | 6.0 (Medium) |
| Vector | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N | AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N |
| User Interaction | None | Passive |
| Attack Requirements | (not modeled in v3.1) | Present |
| Integrity impact | High | None |
The v3.1 score assumes no user interaction and full integrity impact — a worst-case reading. CVSS v4 adds an explicit “Attack Requirements” metric and separates confidentiality/integrity/availability more granularly; it scores this as needing passive user interaction (someone has to be running a session that ingests the untrusted content) and no integrity impact (the bug leaks data, it doesn’t let an attacker modify anything). GitHub’s own advisory database lists the overall severity as “medium,” using the v4 figure as primary.
The practical takeaway if you triage vulnerabilities for a living: don’t cite a bare CVSS number without saying which version it’s from. “9.1 critical” and “6.0 medium” describe the identical bug — the number changes depending on which scoring methodology’s assumptions you accept, not on the underlying risk.
Are You Still Exposed?
| Affected versions | @anthropic-ai/claude-code npm package ≥ 0.2.54, < 2.1.163 |
| Patched version | 2.1.163 |
| Latest version (as of this writing, 2026-09-15) | 2.1.272 |
| CWEs | CWE-183 (Permissive List of Allowed Inputs), CWE-200 (Exposure of Sensitive Information), CWE-515 (Covert Storage Channel) |
Check your version with claude --version or /status inside a session. If you’re on auto-update, you almost certainly already have the fix — it’s been over eight months and roughly a hundred point releases since 2.1.163 shipped. If you pin a specific version for reproducibility (CI images, Docker base layers, an internal mirror), that’s the one place this is worth actually verifying rather than assuming.
The settings.json Pattern Worth Adding Today
Even though this specific hole is closed, the underlying category — “a domain I didn’t choose to trust is fetchable without a prompt” — isn’t unique to Hugging Face. Current Claude Code documentation confirms an important detail: an explicit WebFetch(domain:...) rule in your own deny, ask, or allow list takes precedence over the built-in preapproved set. That means you can override vendor defaults you don’t want, going forward, even for domains Anthropic still pre-approves.
{
"permissions": {
"deny": [
"WebFetch(domain:huggingface.co)"
]
}
}
A few syntax details that matter here, per the current permissions docs:
WebFetch(domain:example.com)matches that exact hostname only.WebFetch(domain:*.example.com)matches any subdomain at any depth — requires Claude Code v2.1.172 or later.WebFetch(domain:*)matches every domain, but it is not the same as a bare"WebFetch"deny rule: the bare rule removes the tool entirely (Claude can’t fetch anything, but sandboxed shell commands are unaffected), whiledomain:*keeps the tool available and refuses each fetch individually, and also blocks sandboxed commands from reaching any host.- Sandboxed commands (Bash running inside Claude Code’s sandbox) don’t inherit WebFetch’s preapproved domain list at all — that’s a separate
sandbox.network.allowedDomainssetting.
If your team ships a shared .claude/settings.json, this is a five-minute addition: enumerate the vendor-preapproved domains you’re not actually using (most repos never touch huggingface.co, for instance) and explicitly deny them. It costs nothing in workflow friction and closes the exact class of bug this CVE represents, independent of whatever Anthropic pre-approves next.
A Reusable Checklist Beyond This One CVE
- Check your version, not just your config. For vendor-hardcoded exceptions, the patch is the only fix — no amount of
permissions.denydiscipline substitutes for staying current. - Audit what’s pre-approved, don’t assume it’s empty.
WebFetchalone auto-approving “documentation domains” is a reasonable default until one of those domains has a public side-channel like a download counter, a pastebin, or a comment system. - Deny domains you don’t need, even ones the vendor trusts. The override capability described above exists specifically so you’re not stuck with someone else’s risk tolerance.
- Remember
WebFetchrestrictions don’t touchBash. Ifcurlorwgetis allowed, domain-scopedWebFetchrules are cosmetic — an agent can still reach any URL through the shell. Pair WebFetch rules withBashdeny rules or the sandbox network allowlist for anything that actually needs to hold. - Treat “pre-approved by the vendor” and “approved by you” as different trust tiers, and write that distinction into whatever internal security review process gates new AI coding tools.
What CLAUDE.md Can’t Fix Here
It’s worth being blunt about scope: none of this belongs in a CLAUDE.md file. Telling Claude in prose “don’t fetch untrusted domains” is context, not enforcement — Anthropic’s own memory documentation says as much, and a prompt-injection attack is, by definition, an attempt to override whatever’s in context. The actual control surface for this class of problem is settings.json permission rules and, for anything that must categorically never happen, a PreToolUse hook — the same distinction we’ve covered in more detail in our piece on Claude Code’s permission and trust-level system.
The same principle extends to how you handle the secrets a compromised WebFetch call could have exposed in the first place: an environment variable sitting in plaintext in .env or a shell profile is available to anything that can read the process environment. Tools like 1Password’s CLI let you inject a secret at the moment a command actually needs it via op run, rather than keeping it resident in the environment for the whole session — one less thing on the table if a future exfiltration channel like this one ever shows up again.
FAQ
Is Claude Code still vulnerable to CVE-2026-54316?
No, if you’re running version 2.1.163 or later. The current version as of September 2026 is 2.1.272. Check with claude --version or /status. Only pinned/mirrored installations on older versions remain at risk.
Could I have blocked this with my own settings.json before the patch shipped?
No. The GitHub advisory’s remediation is solely “update to 2.1.163+.” The vulnerable pre-approval bypassed --allowedTools and user permission rules entirely, so no config on the vulnerable versions would have stopped it.
How do I block a specific domain from WebFetch today?
Add an explicit deny rule to permissions.deny in settings.json, e.g. "WebFetch(domain:huggingface.co)". Current documentation confirms explicit domain rules take precedence over the built-in preapproved set, so this works even for domains Anthropic still pre-approves by default.
Why do different sources report CVE-2026-54316 as both “critical” and “medium”?
Because they’re citing different CVSS versions. The GitHub Security Advisory lists both: 9.1 (Critical) under CVSS v3.1 and 6.0 (Medium) under CVSS v4.0. The v4 score accounts for “Attack Requirements” and treats user interaction as passive rather than none, which pulls the score down; GitHub’s own summary severity field uses the v4 figure.
Related Articles
- Claude Code Permissions and Trust Levels: A Complete Guide
- Claude Code’s Most-Upvoted Issue Hit 5,146 👍 for AGENTS.md Support
- Claude Code vs Codex CLI: A 2026 Comparison
Browse real-world settings.json and CLAUDE.md permission configurations in our gallery.