Zero-Click Account Takeover via HTML Injection in Password Reset Email
The Risk
An attacker could take over any cinema loyalty account simply by getting the victim to open a password reset email. No click was needed. The email looked completely normal, sent from the cinema's real address, but contained an invisible tracking image that quietly leaked the reset code to the attacker the moment the inbox loaded the picture. From there the attacker could log in, see saved payment cards, order history, and personal details, and spend any loyalty points or rewards. There was no visible warning sign for the victim.
The Vulnerability
The password reset endpoint on a cinema chain's loyalty platform accepted a client-supplied resetPasswordLink parameter and embedded the value directly into the HTML email template that was sent to the user. There was no sanitization of HTML special characters before the value was inserted into the href attribute of the "Reset Password" link.
The template effectively rendered:
{`Reset Password`} Server-side, the placeholder {`{0}`} was substituted with the real reset token (a UUID). Because the value was not encoded, an attacker could inject a closing quote followed by an arbitrary HTML tag, breaking out of the href attribute and inserting fully-rendered HTML into the email body.
The Attack
Building the payload
The injected value contained a closing quote, an opening <img> tag pointing at the attacker's server, and the same {`{0}`} placeholder so the server would substitute the real token into the image URL as well. The resulting email body included:
{`
Reset Password`} Exfiltration on email open
Most modern email clients automatically load remote images: Gmail through Google's image proxy, Apple Mail by default, web Outlook through Microsoft's proxy, mobile clients almost universally. The instant the victim opened the email, the email client fetched the attacker's image. That fetch carried the real reset token in the query string. No click on the email's link was required.
Suppressing fallback risk
If the victim did click the visible "Reset Password" link, the href still pointed at the attacker's server. The capture endpoint logged the token and immediately redirected the victim to the cinema's real login page without the token, preventing the victim from using the token first.
Full attack flow
- Attacker sends one unauthenticated POST to the password reset endpoint with the HTML injection payload. No CAPTCHA, no rate limit hit during testing.
- Victim receives an email from the cinema's official sender address, indistinguishable from a legitimate reset email.
- Victim opens the email. The image tag fires automatically. The reset token reaches the attacker's server.
- Attacker visits the public login URL with the captured token and email, sets a new password, and logs in.
Difference from the simpler client-controlled reset URL
An earlier finding on the same endpoint allowed an attacker to point the visible reset link at any URL, but required the victim to click it. This escalation injects fully-rendered HTML into the email body, which is a different vulnerability class (HTML injection in templated email) and removes the click requirement entirely. The two findings address different root causes and require separate fixes.
The Impact
Full account takeover
With the captured token, the attacker completed a password reset on the live login page and took over the victim's loyalty account. The account exposed stored payment methods, order history, name, email, phone, address, and loyalty point balance.
Stealth
The injected image tag is invisible. The victim sees a normal password reset email from the cinema's domain. There is no indicator on the device, in the inbox, or on the account itself that anything unusual happened. If the victim clicked the link they were redirected to the real login page, which makes the attack feel like a misdirected email rather than a compromise.
Email client coverage
The token was exfiltrated reliably from web Gmail, Apple Mail on iOS and macOS, web Outlook, and mobile email apps. Desktop Outlook blocks remote images by default, but many corporate environments override that default. Where Microsoft Defender for Office "Safe Links" is in place, the link itself may be pre-fetched, which can also fire the capture before the user does anything.
Remediation
- Sanitize the
resetPasswordLinkvalue before embedding it in the email template. Encode HTML special characters (",<,>) so injected tags render as text instead of HTML - Better still, remove
resetPasswordLinkfrom the client-accepted parameters entirely. The reset URL should be a server-side configuration per tenant, not something the client supplies - Add a CAPTCHA or rate limit on the password reset endpoint to slow targeted attacks
- Audit the email template engine to confirm no other dynamic fields are inserted into HTML attributes without encoding
- Reduce reset token lifetime and invalidate any unused token when a new one is issued for the same account