Staging Environment: Content and features may be unstable or change without notice.
Search for vulnerabilities
Vulnerability details: VCID-btzb-wm9n-9bc5
Vulnerability ID VCID-btzb-wm9n-9bc5
Aliases CVE-2026-45013
GHSA-gf43-24g3-5hw2
Summary Apostrophe has a Weak Password Recovery Mechanism for Forgotten Password and Improper Input Validation ## Summary ApostropheCMS's password reset flow constructs the reset URL using `req.hostname`, which is derived directly from the attacker-controlled HTTP `Host` header when `apos.baseUrl` is not explicitly configured. An unauthenticated attacker who knows a victim's email address can send a crafted reset request that causes the application to email the victim a reset link pointing to the attacker's domain. When the victim clicks the link, the valid reset token is delivered to the attacker, enabling full account takeover. ## Affected Component `modules/@apostrophecms/login/index.js` — `resetRequest` route Precondition: `passwordReset: true` is set **and** `apos.baseUrl` is not configured. ## Vulnerability Details The `setPrefixUrls` middleware (i18n layer) builds `req.baseUrl` using `req.hostname`: ```js // Simplified from i18n middleware req.baseUrl = `${req.protocol}://${req.hostname}`; req.absoluteUrl = req.baseUrl + req.url; ``` The `resetRequest` handler then passes this tainted value directly into URL construction: ```js const parsed = new URL( req.absoluteUrl, // ← tainted by attacker's Host header self.apos.baseUrl ? undefined : `${req.protocol}://${req.hostname}${port}` // ← also tainted ); parsed.pathname = '/login'; parsed.searchParams.append('reset', reset); // real, valid token parsed.searchParams.append('email', user.email); await self.email(..., { url: parsed.toString() }, ...); // Email sent to victim with URL pointing to attacker-controlled domain ``` When `apos.baseUrl` is configured, it is used unconditionally and the attacker's `Host` header is ignored — that path is **not** vulnerable. ## Attack Scenario 1. Attacker identifies a valid user email (e.g. from the site's public interface). 2. Attacker sends: ``` POST /api/v1/login/reset-request Host: evil.attacker.com Content-Type: application/json {"email": "victim@example.com"} ``` 3. The application emails the victim: ``` Click here to reset your password: http://evil.attacker.com/login?reset=TOKEN&email=victim@example.com ``` 4. Victim clicks the link; attacker's server captures `TOKEN`. 5. Attacker calls the real target's reset endpoint with the captured token and sets a new password — full account takeover. ## Preconditions - `passwordReset: true` configured in login module options (opt-in) - `apos.baseUrl` is **not** set (common in development and some production deployments) - Attacker knows or can enumerate a valid account email ## Impact Full account takeover of any account whose email address is known to the attacker. No authentication or interaction beyond sending a single HTTP request is required from the attacker. The victim need only click a link in a legitimate-looking password reset email from their own site. ## Remediation **Operators (immediate):** Always set `apos.baseUrl` in your configuration: ```js // app.js or module configuration modules: { '@apostrophecms/express': { options: { baseUrl: 'https://yourdomain.com' } } } ``` **Framework fix (recommended):** The `resetRequest` route should refuse to proceed if `apos.baseUrl` is not configured, rather than falling back to the tainted `req.hostname`. Example: ```js // In resetRequest handler if (!self.apos.baseUrl) { throw self.apos.error( 'invalid', 'apos.baseUrl must be configured to enable password reset' ); } const parsed = new URL(self.loginUrl(), self.apos.baseUrl); ``` This eliminates the attacker-controlled input entirely from the URL construction path. ## References - [OWASP: Host Header Injection](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/17-Testing_for_Host_Header_Injection) - [CWE-640: Weak Password Recovery Mechanism for Forgotten Password](https://cwe.mitre.org/data/definitions/640.html)
Status Published
Exploitability None
Weighted Severity None
Risk None
Affected and Fixed Packages Package Details
Weaknesses (2)
No exploits are available.
Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N Found at https://github.com/apostrophecms/apostrophe
Attack Vector (AV) Attack Complexity (AC) Privileges Required (PR) User Interaction (UI) Scope (S) Confidentiality Impact (C) Integrity Impact (I) Availability Impact (A)

network

adjacent_network

local

physical

low

high

none

low

high

none

required

unchanged

changed

high

low

none

high

low

none

high

low

none

Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N Found at https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-gf43-24g3-5hw2
Attack Vector (AV) Attack Complexity (AC) Privileges Required (PR) User Interaction (UI) Scope (S) Confidentiality Impact (C) Integrity Impact (I) Availability Impact (A)

network

adjacent_network

local

physical

low

high

none

low

high

none

required

unchanged

changed

high

low

none

high

low

none

high

low

none

No EPSS data available for this vulnerability.

Date Actor Action Source VulnerableCode Version
2026-06-04T17:03:13.672713+00:00 GithubOSV Importer Import https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-gf43-24g3-5hw2/GHSA-gf43-24g3-5hw2.json 38.6.0