While testing a web application’s profile update functionality, I came across a classic but still very dangerous issue: Stored HTML Injection in the First Name field.
At first glance, it looked like a normal profile page. The user could edit personal details like first name, surname, and email address. Nothing unusual. But when I tested the First Name input field with a simple HTML payload, the application behaved unexpectedly.
Instead of treating my input as plain text, the application rendered it as HTML.
That’s when I confirmed it this was a Stored HTML Injection vulnerability.
What Happened?
In the First Name field, I entered a payload like:
<a style=”position:absolute;margin:50px; background-color: yellow; z-index: 1000;top:50px;padding:100px;font-weight:bold;font-size:45px;color:red;” href=”https://evil.com“>Click here for win 1000$!<a>
After saving the profile and refreshing the page, the content was rendered as an actual clickable link.
Even worse:
- The injected content appeared in the profile page.
- It was stored in the database.
- Every time the profile loaded, the HTML was executed in the browser.
This means the application was not sanitizing user input before storing it and was also not encoding it before rendering.
Why This Is Dangerous
Many developers underestimate HTML Injection because it’s “just HTML.” But in real-world scenarios, this can easily escalate.
Here’s why it matters:
1. Persistent (Stored) Impact
Unlike reflected injection, this payload:
- Is stored in the backend database
- Executes every time the page loads
- Affects anyone who views the profile (including admins)
2. Phishing Within the Application
An attacker can inject something like:
- Fake “Click here to win” banners
- Fake password reset links
- Malicious redirection links
Users will trust it because it appears inside a legitimate website.
3. Path to Stored XSS
If the application allows more complex HTML (like <script> tags or event handlers), this can turn into Stored Cross-Site Scripting (XSS), which is far more severe.
Root Cause
The vulnerability exists because:
- The application does not validate input properly.
- It stores raw HTML in the database.
- It renders user input without output encoding.
This is a failure of input sanitization and output encoding controls.
Proof of Concept:
Press enter or click to view image in full size
Figure 1: The application accepts HTML content in the First Name field without validation.
Impact observed:
- HTML rendered properly.
- Anchor tag clickable.
- Content persisted after logout/login.
This confirms stored HTML injection.
Business Impact
If exploited in production:
- Attackers could inject phishing content.
- Admin panels could display malicious links.
- Brand reputation damage is possible.
- It may lead to credential theft.
- Can escalate to full stored XSS depending on filtering.
In real-world bug bounty programs, this is often categorized under:
- Stored XSS (if script execution possible)
- HTML Injection
- Content Injection
Severity depends on exploitability.
Recommended Fix
Developers should implement:
1. Output Encoding (Primary Fix)
Always encode user-controlled data before rendering in HTML.
Example:
- < should render as <
- > should render as >
2. Input Validation
- Restrict First Name field to alphabetic characters only.
- Reject HTML tags entirely.
3. Content Security Policy (CSP)
Implement strict CSP headers to reduce XSS risk.
4. Use Secure Framework Defaults
Most modern frameworks provide automatic escaping — ensure it is not disabled.
Final Thoughts
This issue is a reminder that even simple input fields like “First Name” can become attack vectors if not handled securely.
Stored HTML Injection may look harmless at first, but in the wrong hands, it becomes a powerful social engineering and phishing tool — especially when injected into trusted pages like account dashboards.
As testers, we must always check:
- Can input accept HTML?
- Is it stored?
- Is it rendered unsafely?
- Can it escalate to script execution?
Small fields. Big impact.