Executive brief
Apostrophe is a popular Node.js-based content management system. When the optional pretty-URL feature is enabled for file serving, the application fails to validate the Host HTTP header when constructing internal proxy URLs. An unauthenticated attacker can exploit this to make the Apostrophe server itself fetch arbitrary URLs on its private network and return the response body, enabling reconnaissance of internal services and potential data exfiltration from verbose error pages or internal proxies.
Technical details
The vulnerability is a Server-Side Request Forgery (SSRF) in the @apostrophecms/file module's pretty-URL handler. When prettyUrls: true is configured, the public GET route constructs an upstream proxy URL by directly embedding the untrusted Host HTTP request header: `proxyUrl = ${req.protocol}://${req.get('host')}${uglyUrl}`. This URL is then passed to fetch() without validation. An attacker can supply an arbitrary Host header (e.g., `Host: internal-service`) to pivot the Apostrophe process into issuing requests to internal network addresses. The path component is constrained by database lookup to `/uploads/attachments/<cuid>-<slug>.<ext>`, narrowing the impact; however, blind SSRF remains viable via response codes and timing side-channels, and data exfiltration occurs against verbose proxies/WAFs. Exploitation requires prettyUrls: true (a documented production option), local uploadfs (the default), and knowledge of at least one valid file slug (publicly enumerable in page content). No fixed release exists as of the advisory date; affected versions are Apostrophe ≤ 4.30.0.
Affected products
- Apostrophe CMS apostrophe ≤ 4.30.0
Timeline
- 2026-07-31: disclosed: Advisory published on OSV and GitHub
- 2026-06-10: patched: Patch merged in PR #5464 / commit 5a88e96 (Latest security q2)