A short recon story about a delayed HTML injection, a surprising phishing vector, and why every output channel deserves the same hardening as your web UI.
When I first started poking around a site I'd signed up for long ago — let's call it xyz.com — I was in bug-hunting mode. I threw common payloads into every visible input field, especially the Name field, because that's one of the easiest places developers forget to sanitize properly.
My test payload was intentionally multi-purpose: a tiny template expression, an HTML anchor, and an input element — designed to probe different rendering contexts at once.
{{8*8}}/"><A HREF=evil.com>HELLO</A">
{{8*8}}"><A HREF="http://evil.com">HELLO</A>I hit Save, checked my profile page, and… nothing useful. The UI showed the name as raw/encoded text — no math evaluated, no clickable link, no input element. I logged it as negative and moved on. The payload became a ghost, quietly stored in xyz.com's database.
The Return of the Phantom 👻
Months later, while skimming my inbox, I saw an email from xyz.com: "Checking your security settings." At first glance it seemed legit — corporate copy, brand styling, the whole nine yards. Then I froze.
Right above the sign-off, where my name should have been dynamically inserted, the exact payload I'd submitted months earlier had been rendered — HTML and all. The template expressions had been evaluated to numbers. The <a> tag had become a clickable link to http://evil.com. Even an actual HTML input field appeared inside the email.
Seeing your own test payload show up, fully alive, in an official email from a trusted service is a mix of validation and dread. Validation because your test worked; dread because an attacker could weaponize the same oversight against many users.

What happened (simple breakdown)
- I submitted a value containing HTML into the Name field.
- xyz.com stored that value in its database.
- The web UI escaped or encoded the value (so it looked safe in-browser).
- Later, an email template interpolated the stored value into an HTML email without proper escaping.
- The mail client rendered the injected HTML, producing a live link and form control — exactly what I injected.
Short version: stored unescaped input → inserted into HTML email → rendered by mail client = stored HTML injection in email.
Why this is dangerous
- Users trust official emails. People are far likelier to click a link from a service they use than from a random site.
- Email clients don't enforce browser CSPs. Many protections that exist in browsers are absent or weaker in mail clients.
- Wide blast radius. If that template is used for security emails or mass notifications, many users could be exposed.
- Social engineering potential. Attackers can craft plausible phishing content with vendor branding and context.
Quick developer checklist — fixes that actually help
- Escape user input when rendering HTML emails. Encode
<,>,&,",'(<,>,&,",'). - Use auto-escaping provided by your template engine; avoid marking user data
safe/raw. - Whitelist characters for name-like fields (letters, digits, spaces, common punctuation).
- Prefer plain-text for critical security emails (password resets, MFA changes).
- Normalize input at ingestion as a second line of defense.
- Test templates with malicious payloads in CI to catch regressions.
- Audit all output sinks: web UI, emails, admin panels, logs, PDFs, mobile push — anything that can render user data.
Final thoughts
A tiny, forgotten field can become a powerful attack vector when stored and later reused in a different context. Don't assume "no visible reflection in the UI = safe." Treat every output channel as hostile, and apply the same rigorous escaping and testing you use for front-end XSS across email templates and other async outputs.