Full Report
Static site generators, such as Jekyll, Hugo, Next.js and others were meant to be so bare bones that security risks were eliminated. This was because, in the past, people were getting pwned with the million plugins they would add to Wordpress. Static site generators have became more dynamic with time though, leading us to this post. Once the static site generators are so popular, many CDN/CI platforms for these sites became available. Netlify and Vercel are a few popular ones. Sam Curry, a different security researcher, was testing a website that used Netlify to host and Next.js for the site generation. Sam sent a message to the author of the post with the following request: https://www.gemini.com/_ipx/w_12812,q_122/https%2f%2flocalhost%2f and response Hostname is missing: localhost The hostname appears to be coming from the URL for some reason. Netlify (similar to Next.js in this way) can build and pull images from remote sources but uses a allowlist of domains that are allowed. The message response above is an error saying that localhost is NOT in the allowlist. If this was the case, then we may have an SSRF vulnerability if this allowlist could be bypassed somehow. Luckily, the Netlify code for this section is open source. While auditing the code, they found another bug. The protocol of the request can be derived from the header x-forwarded-proto. When using this, it concatenates the entire string from the proto without validating it. For instance, the URL https://evil.com/? would be valid evil.com becomes the new domain to be used. This allows for the pulling of arbitrary images. Why is this bad though? It turns out that SVGs are supported with a specific format. Since SVGs are known to be able to execute JavaScript, this gives us XSS on the site. The post claims this is persistent but doesn't really go into details about why. My understanding is that this is a cache poisoning attack on top of the XSS that was found because the X-Forwarded-Proto wasn't in the list of cache keys. A variant on GatsbyJs since they had focused on other things prior. While reviewing the code, they found two instances of proxying code - once for data with any content type and another for any image extension besides SVG. If the development server was running instead of a production version (I used to host my site like this lolz) then an SSRF bug can be used here. One was a full read and the other was blind. Overall, great research! I appreciate the work that Sam and Asset Note are doing at protecting the web eco-system at large for us. Keep up the great work and bug finding!
Analysis Summary
# Vulnerability: SSRF and XSS via Protocol Manipulation in Netlify IPX Image Proxy
## CVE Details
- CVE ID: N/A (Proprietary vulnerability found in Netlify/Gatsby Cloud components, not a standardized CVE at the time of reporting in the article)
- CVSS Score: High (Inferred due to resulting XSS)
- CWE: CWE-918 (Server-Side Request Forgery/SSRF), CWE-79 (Improper Neutralization of Input During Web Page Generation/XSS)
## Affected Systems
- Products: Netlify IPX image proxy (`@netlify/ipx` library), Next.js image optimization (similar findings documented by Sam Curry), Gatsby Cloud Image CDN.
- Versions: Vulnerable versions of `@netlify/ipx` (prior to patch). Specific vulnerable versions for Gatsby Cloud are detailed in their advisory.
- Configurations: Sites hosted on Netlify utilizing the image optimization functionality (e.g., via `_ipx/`) and potentially development server configurations of static site generators, or Gatsby Cloud deployments.
## Vulnerability Description
Two primary vulnerabilities were identified stemming from server-side functionality layered onto static sites:
1. **SSRF via `X-Forwarded-Proto` Manipulation:** In Netlify's IPX library, the request protocol for proxying external assets is derived directly from the user-controlled `x-forwarded-proto` header without validation. If an attacker sends a request with `x-forwarded-proto: https://evil.com/?`, the implementation concatenates `evil.com/?` as the new domain to be used for the request, bypassing the domain allowlist intended for SSRF prevention. This allows SSRF to arbitrary internal or external hosts.
2. **Persistent XSS via SVG Proxying:** The SSRF vulnerability can be leveraged to retrieve arbitrary images. If the attacker requests an SVG image via the compromised proxy mechanism, and the resulting request/response is not correctly keyed in the cache (i.e., the `X-Forwarded-Proto` header is not part of the cache key), this leads to cache poisoning. Since SVGs can contain executable JavaScript, delivering a malicious SVG results in Cross-Site Scripting (XSS) on the victim's browser when the cache entry is served.
A similar vulnerability was noted in GatsbyJS Cloud, leading to high-impact XSS vulnerabilities by misusing the image CDN functionality.
## Exploitation
- Status: PoC available (Internal research by Sam Curry/Asset Note). Exploitation confirmation related to Gatsby Cloud mentioned.
- Complexity: Low to Medium (Requires sending specially crafted HTTP requests targeting the proxy endpoint).
- Attack Vector: Network (Requires ability to send requests to the affected Netlify/Gatsby Cloud hosted endpoint).
## Impact
- Confidentiality: High (If SSRF allows access to internal networks or sensitive server information).
- Integrity: High (Successful cache poisoning leads to persistent XSS).
- Availability: Low (Primarily impacts user sessions/data integrity rather than site uptime).
## Remediation
### Patches
- Netlify: Patches were released for the `@netlify/ipx` library addressing the protocol concatenation issue.
- Gatsby Cloud: A patch was released for the Gatsby Cloud Image CDN; users are directed to the vendor advisory for specific version details.
### Workarounds
- **Restrict incoming headers:** Ensure CDNs or load balancers strip or strictly validate the `X-Forwarded-Proto` header before it reaches the serverless function/proxy logic, adhering only to expected values (`http`, `https`).
- **Audit Allow/Deny lists:** Thoroughly review and tighten any domain or content-type allow lists used by image proxying features.
- **Disable Proxying/Image Optimization:** Temporarily disable external image proxying features if possible until patches are applied.
## Detection
- **Indicators of Compromise:** Look for server logs showing requests to the image optimization endpoint (`/_ipx/` or equivalent) where the URI being requested starts with an unexpected protocol structure or points to unusual internal/external domains bypassing standard allowlists.
- **Detection Methods and Tools:** Network monitoring tools checking for unusual protocols or domain references within HTTP requests targeting image endpoints.
## References
- Vendor Advisory (GatsbyJS): hxxps://www.gatsbyjs.com/blog/vulnerability-patched-in-the-gatsby-cloud-image-cdn/
- Original Research (Sam Curry/AssetNote implied source): Mentioned Sam Curry's blog post for more details (though URL was not fully provided/defanged for linking).