Aug 1, 2026·8 min read·2 visits
Unauthenticated remote attackers can exploit a Host header injection flaw in ApostropheCMS to perform Server-Side Request Forgery (SSRF), mapping internal networks and scanning ports behind firewalls.
An unauthenticated Server-Side Request Forgery (SSRF) vulnerability exists in ApostropheCMS versions up to and including 4.30.0. When the prettyUrls option is enabled in the @apostrophecms/file module, the server constructs internal self-requests using the client-provided HTTP Host header, allowing remote attackers to coerce the server into initiating outbound requests to arbitrary internal or external hosts.
ApostropheCMS is a Node.js-based content management system that relies on a modular architecture. The @apostrophecms/file module manages user uploads and asset hosting. By default, assets uploaded to the system are managed via uploadfs, which can store files either locally on the server's file system or remotely using an object storage provider like Amazon S3. To optimize Search Engine Optimization (SEO), ApostropheCMS includes a prettyUrls feature. When enabled, this feature presents files via clean, human-readable URLs instead of raw path patterns.
The implementation of the clean URL handler registers a public-facing route to process asset requests. If the files are hosted locally, the server must act as a reverse proxy to stream the file contents from the local file system to the remote client. This mechanism exposes an attack surface because the application needs to determine its own network address to fetch the raw file internally.
This analysis examines CVE-2026-53607, an unauthenticated Server-Side Request Forgery (SSRF) vulnerability. The flaw allows external, unauthenticated attackers to manipulate the host resolution step of this proxy process. By supplying a modified HTTP Host header, attackers can force the server to execute outbound HTTP connections to arbitrary addresses.
The exposure is exacerbated in environments where the web server operates inside a trusted local network. Because the request originates from the application's own context, it bypasses firewall perimeters that restrict incoming traffic from the internet. This provides an entry point for internal network scanning.
The root cause of CVE-2026-53607 lies in the insecure handling of the HTTP Host header during internal URL resolution. Under RFC 7230, the Host header is an mandatory field that specifies the target host of the request. Since the Host header is supplied entirely by the client, it must always be treated as untrusted input. The @apostrophecms/file module, however, relied on req.get('host') to reconstruct the server's own origin when resolving relative asset paths.
When the application processes a request for a clean URL, it checks if the underlying asset path starts with a forward slash, which indicates a local relative path. To perform the internal proxy fetch, the server attempts to convert this relative path into an absolute URL. The vulnerable code constructs this URL by directly interpolating the client-provided protocol and Host header.
By modifying the Host header in the incoming HTTP request, an attacker controls the destination authority of the absolute URL. While the path portion of the URL is strictly appended using the static file name retrieved from the database, the target host, port, and scheme are determined entirely by the attacker's payload. This allows an attacker to pivot requests to other network devices.
This design represents a fundamental failure in input boundary validation. Instead of resolving relative URLs against a trusted, hardcoded configuration parameter, the codebase dynamically trusted the header provided in the current TCP session. This is a classic pattern of Host Header Injection leading directly to Server-Side Request Forgery.
The following code block highlights the vulnerable implementation within packages/apostrophe/modules/@apostrophecms/file/index.js:
// VULNERABLE CODE
const uglyUrl = self.apos.attachment.url(file.attachment, {
prettyUrl: false
});
// For relative URLs (local uploadfs, not CDN), resolve
// against the current server's origin so the proxy can
// make the self-request.
const proxyUrl = uglyUrl.startsWith('/')
? `${req.protocol}://${req.get('host')}${uglyUrl}`
: uglyUrl;
return await streamProxy(req, proxyUrl, { error: self.apos.util.error });In this implementation, req.get('host') pulls the Host header value directly from the incoming request. If an attacker passes 169.254.169.254 as the Host, proxyUrl becomes http://169.254.169.254/uploads/attachments/... and is passed directly to the streamProxy utility.
To resolve this vulnerability, the vendor refactored the route handler to eliminate the unsafe string interpolation. The patched code in commit 5a88e9630cbbdde33154ef8abe7557ddf7be418b implements the following changes:
// PATCHED CODE
const uglyUrl = self.apos.attachment.url(file.attachment, {
prettyUrl: false
});
// Relative URLs are now passed directly without Host header reconstruction
return await streamProxy(req, uglyUrl, { error: self.apos.util.error });Under this updated architecture, the relative uglyUrl is passed directly to streamProxy. The streamProxy utility is responsible for safely resolving the relative path against req.baseUrl. This variable refers to a trusted, statically configured origin configured by the system administrator, falling back to the request host only when no secure default exists. This ensures that arbitrary Host header spoofing does not influence outbound socket routing.
To exploit CVE-2026-53607, an attacker must satisfy specific requirements. The target server must be running an affected version of ApostropheCMS, have local file storage active, and have the prettyUrls option explicitly enabled. The attacker does not need any authentication credentials or session tokens to trigger the vulnerability.
The attack begins by locating an existing clean asset path. Because asset paths are public, an attacker can simply browse the target website to find a valid image or file path. The attacker then crafts an HTTP GET request to this path but overrides the standard Host header. For example, to target an internal HTTP server running on 10.0.0.5 at port 8080, the attacker sets the Host header to 10.0.0.5:8080:
GET /uploads/attachments/clxxxxxxx-some-file-slug.jpg HTTP/1.1
Host: 10.0.0.5:8080
User-Agent: Mozilla/5.0
Accept: */*
Connection: closeWhen the request is processed, the ApostropheCMS server makes an outbound connection to http://10.0.0.5:8080/uploads/attachments/clxxxxxxx-some-file-slug.jpg. The internal server at 10.0.0.5 receives this request. If the target server is active, it will respond. Even if the target path does not exist on the internal server, the response timing, HTTP status codes, and connection behaviors are sent back to the attacker.
This behavior allows an attacker to conduct internal port scanning and host discovery. A rapid connection refusal (TCP RST) indicates a closed port on an active host. A connection timeout indicates an inactive host or a firewall rule. A structured response indicates an active service. This reconnaissance allows an attacker to map out internal network infrastructure behind firewalls.
The impact of this SSRF is restricted by the static suffix path. Because the outbound request always appends /uploads/attachments/<filename>, the attacker cannot easily execute arbitrary REST API calls or exploit complex vulnerabilities on internal services that require specific path prefixes. However, significant security risks remain in modern environments.
In cloud environments like Amazon Web Services (AWS) or Google Cloud Platform (GCP), local metadata endpoints (such as 169.254.169.254) expose sensitive information. Under AWS IMDSv1, a GET request to the metadata service can expose host credentials and configuration data. While the hardcoded suffix limits direct access to /latest/meta-data/, vulnerabilities can still arise if internal routing or local DNS servers resolve the path to specific assets.
Furthermore, the SSRF can be used to target internal web applications, databases, and microservices that do not require authentication for local network traffic. The disclosure of headers, response bodies, or timing data can leak proprietary structural details. The CVSS v3.1 score of 3.7 reflects the high complexity due to configuration prerequisites and path restrictions, but the issue remains a serious vector for internal network exposure.
Additionally, the outbound request can be used to perform Distributed Denial of Service (DDoS) reflection attacks. An attacker can leverage multiple vulnerable ApostropheCMS instances to proxy high-volume requests to a targeted external target, hiding the attacker's true origin behind trusted web application servers.
Remediation of CVE-2026-53607 requires upgrading ApostropheCMS to version 4.31.0 or higher. This update removes the insecure string interpolation of the Host header and uses structured base URL resolution. Developers should audit their configurations to ensure that the baseUrl parameter is defined in their environment settings, providing a hardcoded origin for all internal routing tasks.
If an immediate upgrade is not possible, developers must apply temporary workarounds. The most effective workaround is to disable the prettyUrls option in the @apostrophecms/file module configuration. Setting this option to false removes the vulnerable route registration entirely. This change will return asset URLs to their default format but will eliminate the attack vector.
// Disabling prettyUrls configuration workaround
modules: {
'@apostrophecms/file': {
options: {
prettyUrls: false
}
}
}At the network level, security teams should implement egress filtering rules on the application servers. The application hosting ApostropheCMS should be prevented from establishing outbound connections to the local loopback interface, private subnet ranges, and the link-local metadata address 169.254.169.254. These firewall controls prevent SSRF payloads from successfully reaching internal targets.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
apostrophe ApostropheCMS | <= 4.30.0 | 4.31.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 3.7 |
| Exploit Status | Proof-of-Concept |
| CISA KEV Status | Not Listed |
| EPSS Score | 0.00226 |
The web server receives the address of an retrieve-from resource from an untrusted source and retrieves it without validation.
A critical server-side prototype pollution vulnerability in ApostropheCMS versions up to and including 4.30.0 allows authenticated editors to write arbitrary properties to the global Object.prototype via patch operators. Exploiting a confirmed gadget in publicApiCheck() bypasses authorization on all piece-type REST API endpoints framework-wide, persisting for the lifetime of the Node.js process.
A stored Cross-Site Scripting (XSS) vulnerability exists in the @apostrophecms/seo package of the ApostropheCMS ecosystem up to and including version 1.4.2. Unsanitized user inputs for Google Analytics and Google Tag Manager IDs are injected directly into script elements within the document header, enabling authenticated editors to execute arbitrary JavaScript in the context of all site visitors.
A remote denial of service vulnerability exists in the pion/stun package before version 3.1.3. A malformed STUN packet containing a short or empty XOR-MAPPED-ADDRESS attribute triggers a runtime slice-bounds panic during parsing, terminating the entire Go process.
CVE-2026-54908 is a Denial of Service (DoS) vulnerability in the Pion DTLS library, where a malformed ServerKeyExchange message triggers an uncaught out-of-bounds slice read panic during handshake unmarshaling, terminating the hosting application process.
An open redirect vulnerability exists in core-geonetwork from versions 3.12.0 until 4.2.16 and 4.4.11 due to unsafe redirect validation in GeonetworkOAuth2LoginAuthenticationFilter and KeycloakAuthenticationProcessingFilter. An attacker can construct a protocol-relative URL to bypass local redirection checks and redirect authenticated users to malicious external domains.
An observable response discrepancy vulnerability in WPGraphQL versions 2.0.0 through 2.15.0 allows unauthenticated remote attackers to enumerate users and extract public profile metadata. Although the password reset mutation is designed to return a uniform success response to prevent enumeration, a legacy deprecated field resolver bypasses this mechanism by resolving the associated user profile if the target account exists.