GitHub Advisoryadvisory · npm
GHSA-88gm-j2wx-58h6 Cloudflare has SSRF via redirect following through its image-binding-transform endpoint (incomplete fix for GHSA-qpr4)
LOW
Official page ↗
- Aliases
- CVE-2026-41321
- Ecosystem
- npm
- Packages
- @astrojs/cloudflare
- Severity
- Low
- CVSS vector
- CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:L
- Weaknesses
- CWE-918
- Reviewed
- 2026-04-23
Affected packages
• npm @astrojs/cloudflare: < 13.1.10 → fixed in 13.1.10
Description
Summary
The `fetch()` call for remote images in `packages/integrations/cloudflare/src/utils/image-binding-transform.ts` (line 28) uses the default `redirect: 'follow'` behavior. This allows the Cloudflare Worker to follow HTTP redirects to arbitrary URLs, bypassing the `isRemoteAllowed()` domain allowlist check which only validates the initial URL.
All three other image fetch paths in the codebase correctly use `{ redirect: 'manual' }`. This is an incomplete fix for GHSA-qpr4-c339-7vq8.
Confirmed on HEAD.
Root Cause
`image-binding-transform.ts` line 28:
const content = await (isRemotePath(href) ? fetch(imageSrc) : assets.fetch(imageSrc));
Missing `{ redirect: 'manual' }`. The three protected paths:
// image-passthrough-endpoint.ts:23
response = await fetch(href, { redirect: 'manual' });
// assets/endpoint/shared.ts:11
const res = await fetch(src, { redirect: 'manual' });
// assets/utils/remoteProbe.ts:53
const response = await fetch(url, { redirect: 'manual' });
PoC
Demonstrated with Node.js that `fetch()` without `redirect: 'manual'` follows 302 redirects to arbitrary destinations:
# Server A (allowed domain) returns 302 → Server B (internal)
fetch('http://allowed:19741/img.jpg') → follows 302 → hits http://internal:19742/secret
fetch('http://allowed:19741/img.jpg', {redirect:'manual'}) → returns 302, internal server NOT hit
Attack path: attacker finds an open redirect on an allowed domain, crafts `/_image?href=https://allowed-cdn.com/redirect?url=http://internal-service/`, and the Worker follows the redirect to the unauthorized destination.
Impact
Bypasses the `image.domains` and `image.remotePatterns` allowlist for the default Cloudflare image service (`cloudflare-binding`). Enables blind SSRF to domains not in the allowlist. Same vulnerability class as GHSA-qpr4-c339-7vq8 (HIGH) which fixed the passthrough endpoint but missed this one.
Suggested Fix
const content = await (isRemotePath(href) ? fetch(imageSrc, { redirect: 'manual' }) : assets.fetch(imageSrc));
Related
Alias · CVE (1)
- CVE-2026-41321 @astrojs/cloudflare is an SSR adapter for use with Cloudflare Workers targets. vulnerability
Weakness · CWE (1)
- CWE-918 Server-Side Request Forgery weakness
References
- https://github.com/withastro/astro/security/advisories/GHSA-88gm-j2wx-58h6 web
- https://nvd.nist.gov/vuln/detail/CVE-2026-41321 advisory
- https://github.com/withastro/astro/commit/a43eb4b40b4f81530e3c9b5e2959495900320433 web
- https://github.com/advisories/GHSA-qpr4-c339-7vq8 advisory
- https://github.com/withastro/astro package
- https://github.com/withastro/astro/releases/tag/%40astrojs%2Fcloudflare%4013.1.10 web