GHSA-3843-RR4G-M8JQ
Vulnerability from github – Published: 2026-03-27 17:56 – Updated: 2026-03-30 20:11Description
A vulnerability has been identified in express-xss-sanitizer (<= 2.0.1) where restrictive sanitization configurations are silently ignored.
When a developer explicitly sets:
allowedTags: [] allowedAttributes: {}
the library incorrectly treats these values as "not provided" due to length/emptiness checks, and falls back to sanitize-html's default configuration.
As a result, instead of stripping all HTML tags and attributes, the sanitizer allows a permissive set of tags (e.g., <a>, <p>, <div>, etc.) and attributes (e.g., href on <a>).
This behavior violates the expected API contract and may lead to security issues such as content injection or XSS, depending on how the sanitized output is used.
Impact
Developers intending to fully strip HTML content by providing empty allowedTags or allowedAttributes configurations may unknowingly allow a wide range of HTML elements and attributes.
This can result in:
- Injection of unintended HTML content (e.g., <div>, <table>, headings)
- Injection of links via<a href="...">
- Potential XSS vectors depending on downstream usage
The impact depends on how the sanitized output is rendered or consumed, but the root issue is a mismatch between developer intent and actual behavior.
Proof of Concept
const { sanitize } = require('express-xss-sanitizer');
const sanitizeHtml = require('sanitize-html');
const input = '<a href="http://evil.com">click</a><p>phish</p>';
// Using express-xss-sanitizer (v2.0.1)
sanitize(input, { allowedTags: [], allowedAttributes: {} });
// => '<a href="http://evil.com">click</a><p>phish</p>'
// Expected behavior (sanitize-html directly)
sanitizeHtml(input, { allowedTags: [], allowedAttributes: {} });
// => 'clickphish'
Root Cause
The issue was caused by validation logic that checked for non-empty arrays/objects:
- allowedTags required length > 0
- allowedAttributes required Object.keys(...).length > 0
This caused empty configurations ([]) and ({}) to be ignored, resulting in fallback to default permissive settings.
Fix
The validation logic has been updated to respect explicitly provided empty configurations.
Now, if allowedTags or allowedAttributes are provided (even if empty), they are passed directly to sanitize-html without being overridden.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "express-xss-sanitizer"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.0.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33979"
],
"database_specific": {
"cwe_ids": [
"CWE-183",
"CWE-79"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-27T17:56:45Z",
"nvd_published_at": "2026-03-27T22:16:22Z",
"severity": "HIGH"
},
"details": "## Description\nA vulnerability has been identified in express-xss-sanitizer (\u003c= 2.0.1) where restrictive sanitization configurations are silently ignored.\n\nWhen a developer explicitly sets:\n\n allowedTags: []\n allowedAttributes: {}\n\nthe library incorrectly treats these values as \"not provided\" due to length/emptiness checks, and falls back to sanitize-html\u0027s default configuration.\n\nAs a result, instead of stripping all HTML tags and attributes, the sanitizer allows a permissive set of tags ``` (e.g., \u003ca\u003e, \u003cp\u003e, \u003cdiv\u003e, etc.) and attributes (e.g., href on \u003ca\u003e)```.\n\nThis behavior violates the expected API contract and may lead to security issues such as content injection or XSS, depending on how the sanitized output is used.\n\n## Impact\n\nDevelopers intending to fully strip HTML content by providing empty allowedTags or allowedAttributes configurations may unknowingly allow a wide range of HTML elements and attributes.\n\nThis can result in:\n- Injection of unintended HTML content ```(e.g., \u003cdiv\u003e, \u003ctable\u003e, headings)```\n- Injection of links via``` \u003ca href=\"...\"\u003e```\n- Potential XSS vectors depending on downstream usage\n\nThe impact depends on how the sanitized output is rendered or consumed, but the root issue is a mismatch between developer intent and actual behavior.\n\n## Proof of Concept\n\n```javascript\nconst { sanitize } = require(\u0027express-xss-sanitizer\u0027);\nconst sanitizeHtml = require(\u0027sanitize-html\u0027);\n\nconst input = \u0027\u003ca href=\"http://evil.com\"\u003eclick\u003c/a\u003e\u003cp\u003ephish\u003c/p\u003e\u0027;\n\n// Using express-xss-sanitizer (v2.0.1)\nsanitize(input, { allowedTags: [], allowedAttributes: {} });\n// =\u003e \u0027\u003ca href=\"http://evil.com\"\u003eclick\u003c/a\u003e\u003cp\u003ephish\u003c/p\u003e\u0027\n\n// Expected behavior (sanitize-html directly)\nsanitizeHtml(input, { allowedTags: [], allowedAttributes: {} });\n// =\u003e \u0027clickphish\u0027\n```\n\n## Root Cause\nThe issue was caused by validation logic that checked for non-empty arrays/objects:\n\n- allowedTags required length \u003e 0\n- allowedAttributes required Object.keys(...).length \u003e 0\n\nThis caused empty configurations ([]) and ({}) to be ignored, resulting in fallback to default permissive settings.\n\n## Fix\nThe validation logic has been updated to respect explicitly provided empty configurations.\n\nNow, if allowedTags or allowedAttributes are provided (even if empty), they are passed directly to sanitize-html without being overridden.",
"id": "GHSA-3843-rr4g-m8jq",
"modified": "2026-03-30T20:11:03Z",
"published": "2026-03-27T17:56:45Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/AhmedAdelFahim/express-xss-sanitizer/security/advisories/GHSA-3843-rr4g-m8jq"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33979"
},
{
"type": "WEB",
"url": "https://github.com/AhmedAdelFahim/express-xss-sanitizer/commit/5623009ef11dcf095c163a38dea07b9cc22ad19f"
},
{
"type": "PACKAGE",
"url": "https://github.com/AhmedAdelFahim/express-xss-sanitizer"
},
{
"type": "WEB",
"url": "https://github.com/AhmedAdelFahim/express-xss-sanitizer/releases/tag/v2.0.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Express XSS Sanitizer: allowedTags/allowedAttributes bypass leads to permissive sanitization (XSS risk)"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.