CVE-2025-15284 (GCVE-0-2025-15284)
Vulnerability from cvelistv5 – Published: 2025-12-29 22:56 – Updated: 2025-12-30 15:57
VLAI?
Title
arrayLimit bypass in bracket notation allows DoS via memory exhaustion
Summary
Improper Input Validation vulnerability in qs (parse modules) allows HTTP DoS.This issue affects qs: < 6.14.1.
SummaryThe arrayLimit option in qs does not enforce limits for bracket notation (a[]=1&a[]=2), allowing attackers to cause denial-of-service via memory exhaustion. Applications using arrayLimit for DoS protection are vulnerable.
DetailsThe arrayLimit option only checks limits for indexed notation (a[0]=1&a[1]=2) but completely bypasses it for bracket notation (a[]=1&a[]=2).
Vulnerable code (lib/parse.js:159-162):
if (root === '[]' && options.parseArrays) {
obj = utils.combine([], leaf); // No arrayLimit check
}
Working code (lib/parse.js:175):
else if (index <= options.arrayLimit) { // Limit checked here
obj = [];
obj[index] = leaf;
}
The bracket notation handler at line 159 uses utils.combine([], leaf) without validating against options.arrayLimit, while indexed notation at line 175 checks index <= options.arrayLimit before creating arrays.
PoCTest 1 - Basic bypass:
npm install qs
const qs = require('qs');
const result = qs.parse('a[]=1&a[]=2&a[]=3&a[]=4&a[]=5&a[]=6', { arrayLimit: 5 });
console.log(result.a.length); // Output: 6 (should be max 5)
Test 2 - DoS demonstration:
const qs = require('qs');
const attack = 'a[]=' + Array(10000).fill('x').join('&a[]=');
const result = qs.parse(attack, { arrayLimit: 100 });
console.log(result.a.length); // Output: 10000 (should be max 100)
Configuration:
* arrayLimit: 5 (test 1) or arrayLimit: 100 (test 2)
* Use bracket notation: a[]=value (not indexed a[0]=value)
ImpactDenial of Service via memory exhaustion. Affects applications using qs.parse() with user-controlled input and arrayLimit for protection.
Attack scenario:
* Attacker sends HTTP request: GET /api/search?filters[]=x&filters[]=x&...&filters[]=x (100,000+ times)
* Application parses with qs.parse(query, { arrayLimit: 100 })
* qs ignores limit, parses all 100,000 elements into array
* Server memory exhausted → application crashes or becomes unresponsive
* Service unavailable for all users
Real-world impact:
* Single malicious request can crash server
* No authentication required
* Easy to automate and scale
* Affects any endpoint parsing query strings with bracket notation
Severity ?
CWE
- CWE-20 - Improper Input Validation
Assigner
References
| URL | Tags | |
|---|---|---|
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2025-15284",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "yes"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2025-12-30T14:55:26.031863Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2025-12-30T15:57:41.402Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"collectionURL": "https://npmjs.com/qs",
"defaultStatus": "affected",
"modules": [
"parse"
],
"packageName": "qs",
"repo": "https://github.com/ljharb/qs",
"versions": [
{
"status": "affected",
"version": "\u003c 6.14.1",
"versionType": "semver"
}
]
}
],
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "Improper Input Validation vulnerability in qs (parse modules) allows HTTP DoS.\u003cp\u003eThis issue affects qs: \u0026lt; 6.14.1.\u003c/p\u003e\u003ch3\u003e\u003cbr\u003eSummary\u003c/h3\u003e\u003cp\u003eThe \u003ccode\u003earrayLimit\u003c/code\u003e\u0026nbsp;option in qs does not enforce limits for bracket notation (\u003ccode\u003ea[]=1\u0026amp;a[]=2\u003c/code\u003e), allowing attackers to cause denial-of-service via memory exhaustion. Applications using \u003ccode\u003earrayLimit\u003c/code\u003e\u0026nbsp;for DoS protection are vulnerable.\u003c/p\u003e\u003ch3\u003eDetails\u003c/h3\u003e\u003cp\u003eThe \u003ccode\u003earrayLimit\u003c/code\u003e\u0026nbsp;option only checks limits for indexed notation (\u003ccode\u003ea[0]=1\u0026amp;a[1]=2\u003c/code\u003e) but completely bypasses it for bracket notation (\u003ccode\u003ea[]=1\u0026amp;a[]=2\u003c/code\u003e).\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eVulnerable code\u003c/strong\u003e\u0026nbsp;(\u003ccode\u003elib/parse.js:159-162\u003c/code\u003e):\u003c/p\u003e\u003cdiv\u003e\u003cpre\u003eif (root === \u0027[]\u0027 \u0026amp;\u0026amp; options.parseArrays) {\n obj = utils.combine([], leaf); // No arrayLimit check\n}\u003c/pre\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eWorking code\u003c/strong\u003e\u0026nbsp;(\u003ccode\u003elib/parse.js:175\u003c/code\u003e):\u003c/p\u003e\u003cdiv\u003e\u003cpre\u003eelse if (index \u0026lt;= options.arrayLimit) { // Limit checked here\n obj = [];\n obj[index] = leaf;\n}\u003c/pre\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\u003cp\u003eThe bracket notation handler at line 159 uses \u003ccode\u003eutils.combine([], leaf)\u003c/code\u003e\u0026nbsp;without validating against \u003ccode\u003eoptions.arrayLimit\u003c/code\u003e, while indexed notation at line 175 checks \u003ccode\u003eindex \u0026lt;= options.arrayLimit\u003c/code\u003e\u0026nbsp;before creating arrays.\u003c/p\u003e\u003ch3\u003ePoC\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003eTest 1 - Basic bypass:\u003c/strong\u003e\u003c/p\u003e\u003cdiv\u003e\u003cpre\u003enpm install qs\u003c/pre\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\u003cdiv\u003e\u003cpre\u003econst qs = require(\u0027qs\u0027);\nconst result = qs.parse(\u0027a[]=1\u0026amp;a[]=2\u0026amp;a[]=3\u0026amp;a[]=4\u0026amp;a[]=5\u0026amp;a[]=6\u0027, { arrayLimit: 5 });\nconsole.log(result.a.length); // Output: 6 (should be max 5)\u003c/pre\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eTest 2 - DoS demonstration:\u003c/strong\u003e\u003c/p\u003e\u003cdiv\u003e\u003cpre\u003econst qs = require(\u0027qs\u0027);\nconst attack = \u0027a[]=\u0027 + Array(10000).fill(\u0027x\u0027).join(\u0027\u0026amp;a[]=\u0027);\nconst result = qs.parse(attack, { arrayLimit: 100 });\nconsole.log(result.a.length); // Output: 10000 (should be max 100)\u003c/pre\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eConfiguration:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003earrayLimit: 5\u003c/code\u003e\u0026nbsp;(test 1) or \u003ccode\u003earrayLimit: 100\u003c/code\u003e\u0026nbsp;(test 2)\u003c/li\u003e\u003cli\u003eUse bracket notation: \u003ccode\u003ea[]=value\u003c/code\u003e\u0026nbsp;(not indexed \u003ccode\u003ea[0]=value\u003c/code\u003e)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eImpact\u003c/h3\u003e\u003cp\u003eDenial of Service via memory exhaustion. Affects applications using \u003ccode\u003eqs.parse()\u003c/code\u003e\u0026nbsp;with user-controlled input and \u003ccode\u003earrayLimit\u003c/code\u003e\u0026nbsp;for protection.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eAttack scenario:\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eAttacker sends HTTP request: \u003ccode\u003eGET /api/search?filters[]=x\u0026amp;filters[]=x\u0026amp;...\u0026amp;filters[]=x\u003c/code\u003e\u0026nbsp;(100,000+ times)\u003c/li\u003e\u003cli\u003eApplication parses with \u003ccode\u003eqs.parse(query, { arrayLimit: 100 })\u003c/code\u003e\u003c/li\u003e\u003cli\u003eqs ignores limit, parses all 100,000 elements into array\u003c/li\u003e\u003cli\u003eServer memory exhausted \u2192 application crashes or becomes unresponsive\u003c/li\u003e\u003cli\u003eService unavailable for all users\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003eReal-world impact:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003eSingle malicious request can crash server\u003c/li\u003e\u003cli\u003eNo authentication required\u003c/li\u003e\u003cli\u003eEasy to automate and scale\u003c/li\u003e\u003cli\u003eAffects any endpoint parsing query strings with bracket notation\u003c/li\u003e\u003c/ul\u003e"
}
],
"value": "Improper Input Validation vulnerability in qs (parse modules) allows HTTP DoS.This issue affects qs: \u003c 6.14.1.\n\n\nSummaryThe arrayLimit\u00a0option in qs does not enforce limits for bracket notation (a[]=1\u0026a[]=2), allowing attackers to cause denial-of-service via memory exhaustion. Applications using arrayLimit\u00a0for DoS protection are vulnerable.\n\nDetailsThe arrayLimit\u00a0option only checks limits for indexed notation (a[0]=1\u0026a[1]=2) but completely bypasses it for bracket notation (a[]=1\u0026a[]=2).\n\nVulnerable code\u00a0(lib/parse.js:159-162):\n\nif (root === \u0027[]\u0027 \u0026\u0026 options.parseArrays) {\n obj = utils.combine([], leaf); // No arrayLimit check\n}\n\n\n\n\n\nWorking code\u00a0(lib/parse.js:175):\n\nelse if (index \u003c= options.arrayLimit) { // Limit checked here\n obj = [];\n obj[index] = leaf;\n}\n\n\n\n\n\nThe bracket notation handler at line 159 uses utils.combine([], leaf)\u00a0without validating against options.arrayLimit, while indexed notation at line 175 checks index \u003c= options.arrayLimit\u00a0before creating arrays.\n\nPoCTest 1 - Basic bypass:\n\nnpm install qs\n\n\n\n\n\nconst qs = require(\u0027qs\u0027);\nconst result = qs.parse(\u0027a[]=1\u0026a[]=2\u0026a[]=3\u0026a[]=4\u0026a[]=5\u0026a[]=6\u0027, { arrayLimit: 5 });\nconsole.log(result.a.length); // Output: 6 (should be max 5)\n\n\n\n\n\nTest 2 - DoS demonstration:\n\nconst qs = require(\u0027qs\u0027);\nconst attack = \u0027a[]=\u0027 + Array(10000).fill(\u0027x\u0027).join(\u0027\u0026a[]=\u0027);\nconst result = qs.parse(attack, { arrayLimit: 100 });\nconsole.log(result.a.length); // Output: 10000 (should be max 100)\n\n\n\n\n\nConfiguration:\n\n * arrayLimit: 5\u00a0(test 1) or arrayLimit: 100\u00a0(test 2)\n * Use bracket notation: a[]=value\u00a0(not indexed a[0]=value)\n\n\nImpactDenial of Service via memory exhaustion. Affects applications using qs.parse()\u00a0with user-controlled input and arrayLimit\u00a0for protection.\n\nAttack scenario:\n\n * Attacker sends HTTP request: GET /api/search?filters[]=x\u0026filters[]=x\u0026...\u0026filters[]=x\u00a0(100,000+ times)\n * Application parses with qs.parse(query, { arrayLimit: 100 })\n * qs ignores limit, parses all 100,000 elements into array\n * Server memory exhausted \u2192 application crashes or becomes unresponsive\n * Service unavailable for all users\nReal-world impact:\n\n * Single malicious request can crash server\n * No authentication required\n * Easy to automate and scale\n * Affects any endpoint parsing query strings with bracket notation"
}
],
"impacts": [
{
"capecId": "CAPEC-469",
"descriptions": [
{
"lang": "en",
"value": "CAPEC-469 HTTP DoS"
}
]
}
],
"metrics": [
{
"cvssV4_0": {
"Automatable": "NOT_DEFINED",
"Recovery": "NOT_DEFINED",
"Safety": "NOT_DEFINED",
"attackComplexity": "LOW",
"attackRequirements": "NONE",
"attackVector": "NETWORK",
"baseScore": 8.7,
"baseSeverity": "HIGH",
"exploitMaturity": "NOT_DEFINED",
"privilegesRequired": "NONE",
"providerUrgency": "NOT_DEFINED",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "NONE",
"userInteraction": "NONE",
"valueDensity": "NOT_DEFINED",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"version": "4.0",
"vulnAvailabilityImpact": "HIGH",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "NONE",
"vulnerabilityResponseEffort": "NOT_DEFINED"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
},
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 7.5,
"baseSeverity": "HIGH",
"confidentialityImpact": "NONE",
"integrityImpact": "NONE",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-20",
"description": "CWE-20 Improper Input Validation",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2025-12-29T22:56:45.240Z",
"orgId": "7ffcee3d-2c14-4c3e-b844-86c6a321a158",
"shortName": "harborist"
},
"references": [
{
"tags": [
"vendor-advisory"
],
"url": "https://github.com/ljharb/qs/security/advisories/GHSA-6rw7-vpxm-498p"
},
{
"tags": [
"patch"
],
"url": "https://github.com/ljharb/qs/commit/3086902ecf7f088d0d1803887643ac6c03d415b9"
}
],
"source": {
"discovery": "UNKNOWN"
},
"title": "arrayLimit bypass in bracket notation allows DoS via memory exhaustion",
"x_generator": {
"engine": "Vulnogram 0.5.0"
}
}
},
"cveMetadata": {
"assignerOrgId": "7ffcee3d-2c14-4c3e-b844-86c6a321a158",
"assignerShortName": "harborist",
"cveId": "CVE-2025-15284",
"datePublished": "2025-12-29T22:56:45.240Z",
"dateReserved": "2025-12-29T21:36:51.399Z",
"dateUpdated": "2025-12-30T15:57:41.402Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"vulnerability-lookup:meta": {
"nvd": "{\"cve\":{\"id\":\"CVE-2025-15284\",\"sourceIdentifier\":\"7ffcee3d-2c14-4c3e-b844-86c6a321a158\",\"published\":\"2025-12-29T23:15:42.703\",\"lastModified\":\"2025-12-29T23:15:42.703\",\"vulnStatus\":\"Received\",\"cveTags\":[],\"descriptions\":[{\"lang\":\"en\",\"value\":\"Improper Input Validation vulnerability in qs (parse modules) allows HTTP DoS.This issue affects qs: \u003c 6.14.1.\\n\\n\\nSummaryThe arrayLimit\u00a0option in qs does not enforce limits for bracket notation (a[]=1\u0026a[]=2), allowing attackers to cause denial-of-service via memory exhaustion. Applications using arrayLimit\u00a0for DoS protection are vulnerable.\\n\\nDetailsThe arrayLimit\u00a0option only checks limits for indexed notation (a[0]=1\u0026a[1]=2) but completely bypasses it for bracket notation (a[]=1\u0026a[]=2).\\n\\nVulnerable code\u00a0(lib/parse.js:159-162):\\n\\nif (root === \u0027[]\u0027 \u0026\u0026 options.parseArrays) {\\n obj = utils.combine([], leaf); // No arrayLimit check\\n}\\n\\n\\n\\n\\n\\nWorking code\u00a0(lib/parse.js:175):\\n\\nelse if (index \u003c= options.arrayLimit) { // Limit checked here\\n obj = [];\\n obj[index] = leaf;\\n}\\n\\n\\n\\n\\n\\nThe bracket notation handler at line 159 uses utils.combine([], leaf)\u00a0without validating against options.arrayLimit, while indexed notation at line 175 checks index \u003c= options.arrayLimit\u00a0before creating arrays.\\n\\nPoCTest 1 - Basic bypass:\\n\\nnpm install qs\\n\\n\\n\\n\\n\\nconst qs = require(\u0027qs\u0027);\\nconst result = qs.parse(\u0027a[]=1\u0026a[]=2\u0026a[]=3\u0026a[]=4\u0026a[]=5\u0026a[]=6\u0027, { arrayLimit: 5 });\\nconsole.log(result.a.length); // Output: 6 (should be max 5)\\n\\n\\n\\n\\n\\nTest 2 - DoS demonstration:\\n\\nconst qs = require(\u0027qs\u0027);\\nconst attack = \u0027a[]=\u0027 + Array(10000).fill(\u0027x\u0027).join(\u0027\u0026a[]=\u0027);\\nconst result = qs.parse(attack, { arrayLimit: 100 });\\nconsole.log(result.a.length); // Output: 10000 (should be max 100)\\n\\n\\n\\n\\n\\nConfiguration:\\n\\n * arrayLimit: 5\u00a0(test 1) or arrayLimit: 100\u00a0(test 2)\\n * Use bracket notation: a[]=value\u00a0(not indexed a[0]=value)\\n\\n\\nImpactDenial of Service via memory exhaustion. Affects applications using qs.parse()\u00a0with user-controlled input and arrayLimit\u00a0for protection.\\n\\nAttack scenario:\\n\\n * Attacker sends HTTP request: GET /api/search?filters[]=x\u0026filters[]=x\u0026...\u0026filters[]=x\u00a0(100,000+ times)\\n * Application parses with qs.parse(query, { arrayLimit: 100 })\\n * qs ignores limit, parses all 100,000 elements into array\\n * Server memory exhausted \u2192 application crashes or becomes unresponsive\\n * Service unavailable for all users\\nReal-world impact:\\n\\n * Single malicious request can crash server\\n * No authentication required\\n * Easy to automate and scale\\n * Affects any endpoint parsing query strings with bracket notation\"}],\"metrics\":{\"cvssMetricV40\":[{\"source\":\"7ffcee3d-2c14-4c3e-b844-86c6a321a158\",\"type\":\"Secondary\",\"cvssData\":{\"version\":\"4.0\",\"vectorString\":\"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/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:X/R:X/V:X/RE:X/U:X\",\"baseScore\":8.7,\"baseSeverity\":\"HIGH\",\"attackVector\":\"NETWORK\",\"attackComplexity\":\"LOW\",\"attackRequirements\":\"NONE\",\"privilegesRequired\":\"NONE\",\"userInteraction\":\"NONE\",\"vulnConfidentialityImpact\":\"NONE\",\"vulnIntegrityImpact\":\"NONE\",\"vulnAvailabilityImpact\":\"HIGH\",\"subConfidentialityImpact\":\"NONE\",\"subIntegrityImpact\":\"NONE\",\"subAvailabilityImpact\":\"NONE\",\"exploitMaturity\":\"NOT_DEFINED\",\"confidentialityRequirement\":\"NOT_DEFINED\",\"integrityRequirement\":\"NOT_DEFINED\",\"availabilityRequirement\":\"NOT_DEFINED\",\"modifiedAttackVector\":\"NOT_DEFINED\",\"modifiedAttackComplexity\":\"NOT_DEFINED\",\"modifiedAttackRequirements\":\"NOT_DEFINED\",\"modifiedPrivilegesRequired\":\"NOT_DEFINED\",\"modifiedUserInteraction\":\"NOT_DEFINED\",\"modifiedVulnConfidentialityImpact\":\"NOT_DEFINED\",\"modifiedVulnIntegrityImpact\":\"NOT_DEFINED\",\"modifiedVulnAvailabilityImpact\":\"NOT_DEFINED\",\"modifiedSubConfidentialityImpact\":\"NOT_DEFINED\",\"modifiedSubIntegrityImpact\":\"NOT_DEFINED\",\"modifiedSubAvailabilityImpact\":\"NOT_DEFINED\",\"Safety\":\"NOT_DEFINED\",\"Automatable\":\"NOT_DEFINED\",\"Recovery\":\"NOT_DEFINED\",\"valueDensity\":\"NOT_DEFINED\",\"vulnerabilityResponseEffort\":\"NOT_DEFINED\",\"providerUrgency\":\"NOT_DEFINED\"}}],\"cvssMetricV31\":[{\"source\":\"7ffcee3d-2c14-4c3e-b844-86c6a321a158\",\"type\":\"Secondary\",\"cvssData\":{\"version\":\"3.1\",\"vectorString\":\"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H\",\"baseScore\":7.5,\"baseSeverity\":\"HIGH\",\"attackVector\":\"NETWORK\",\"attackComplexity\":\"LOW\",\"privilegesRequired\":\"NONE\",\"userInteraction\":\"NONE\",\"scope\":\"UNCHANGED\",\"confidentialityImpact\":\"NONE\",\"integrityImpact\":\"NONE\",\"availabilityImpact\":\"HIGH\"},\"exploitabilityScore\":3.9,\"impactScore\":3.6}]},\"weaknesses\":[{\"source\":\"7ffcee3d-2c14-4c3e-b844-86c6a321a158\",\"type\":\"Secondary\",\"description\":[{\"lang\":\"en\",\"value\":\"CWE-20\"}]}],\"references\":[{\"url\":\"https://github.com/ljharb/qs/commit/3086902ecf7f088d0d1803887643ac6c03d415b9\",\"source\":\"7ffcee3d-2c14-4c3e-b844-86c6a321a158\"},{\"url\":\"https://github.com/ljharb/qs/security/advisories/GHSA-6rw7-vpxm-498p\",\"source\":\"7ffcee3d-2c14-4c3e-b844-86c6a321a158\"}]}}",
"vulnrichment": {
"containers": "{\"adp\": [{\"title\": \"CISA ADP Vulnrichment\", \"metrics\": [{\"other\": {\"type\": \"ssvc\", \"content\": {\"id\": \"CVE-2025-15284\", \"role\": \"CISA Coordinator\", \"options\": [{\"Exploitation\": \"none\"}, {\"Automatable\": \"yes\"}, {\"Technical Impact\": \"partial\"}], \"version\": \"2.0.3\", \"timestamp\": \"2025-12-30T14:55:26.031863Z\"}}}], \"providerMetadata\": {\"orgId\": \"134c704f-9b21-4f2e-91b3-4a467353bcc0\", \"shortName\": \"CISA-ADP\", \"dateUpdated\": \"2025-12-30T15:55:05.860Z\"}}], \"cna\": {\"title\": \"arrayLimit bypass in bracket notation allows DoS via memory exhaustion\", \"source\": {\"discovery\": \"UNKNOWN\"}, \"impacts\": [{\"capecId\": \"CAPEC-469\", \"descriptions\": [{\"lang\": \"en\", \"value\": \"CAPEC-469 HTTP DoS\"}]}], \"metrics\": [{\"format\": \"CVSS\", \"cvssV4_0\": {\"Safety\": \"NOT_DEFINED\", \"version\": \"4.0\", \"Recovery\": \"NOT_DEFINED\", \"baseScore\": 8.7, \"Automatable\": \"NOT_DEFINED\", \"attackVector\": \"NETWORK\", \"baseSeverity\": \"HIGH\", \"valueDensity\": \"NOT_DEFINED\", \"vectorString\": \"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N\", \"exploitMaturity\": \"NOT_DEFINED\", \"providerUrgency\": \"NOT_DEFINED\", \"userInteraction\": \"NONE\", \"attackComplexity\": \"LOW\", \"attackRequirements\": \"NONE\", \"privilegesRequired\": \"NONE\", \"subIntegrityImpact\": \"NONE\", \"vulnIntegrityImpact\": \"NONE\", \"subAvailabilityImpact\": \"NONE\", \"vulnAvailabilityImpact\": \"HIGH\", \"subConfidentialityImpact\": \"NONE\", \"vulnConfidentialityImpact\": \"NONE\", \"vulnerabilityResponseEffort\": \"NOT_DEFINED\"}, \"scenarios\": [{\"lang\": \"en\", \"value\": \"GENERAL\"}]}, {\"format\": \"CVSS\", \"cvssV3_1\": {\"scope\": \"UNCHANGED\", \"version\": \"3.1\", \"baseScore\": 7.5, \"attackVector\": \"NETWORK\", \"baseSeverity\": \"HIGH\", \"vectorString\": \"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H\", \"integrityImpact\": \"NONE\", \"userInteraction\": \"NONE\", \"attackComplexity\": \"LOW\", \"availabilityImpact\": \"HIGH\", \"privilegesRequired\": \"NONE\", \"confidentialityImpact\": \"NONE\"}, \"scenarios\": [{\"lang\": \"en\", \"value\": \"GENERAL\"}]}], \"affected\": [{\"repo\": \"https://github.com/ljharb/qs\", \"modules\": [\"parse\"], \"versions\": [{\"status\": \"affected\", \"version\": \"\u003c 6.14.1\", \"versionType\": \"semver\"}], \"packageName\": \"qs\", \"collectionURL\": \"https://npmjs.com/qs\", \"defaultStatus\": \"affected\"}], \"references\": [{\"url\": \"https://github.com/ljharb/qs/security/advisories/GHSA-6rw7-vpxm-498p\", \"tags\": [\"vendor-advisory\"]}, {\"url\": \"https://github.com/ljharb/qs/commit/3086902ecf7f088d0d1803887643ac6c03d415b9\", \"tags\": [\"patch\"]}], \"x_generator\": {\"engine\": \"Vulnogram 0.5.0\"}, \"descriptions\": [{\"lang\": \"en\", \"value\": \"Improper Input Validation vulnerability in qs (parse modules) allows HTTP DoS.This issue affects qs: \u003c 6.14.1.\\n\\n\\nSummaryThe arrayLimit\\u00a0option in qs does not enforce limits for bracket notation (a[]=1\u0026a[]=2), allowing attackers to cause denial-of-service via memory exhaustion. Applications using arrayLimit\\u00a0for DoS protection are vulnerable.\\n\\nDetailsThe arrayLimit\\u00a0option only checks limits for indexed notation (a[0]=1\u0026a[1]=2) but completely bypasses it for bracket notation (a[]=1\u0026a[]=2).\\n\\nVulnerable code\\u00a0(lib/parse.js:159-162):\\n\\nif (root === \u0027[]\u0027 \u0026\u0026 options.parseArrays) {\\n obj = utils.combine([], leaf); // No arrayLimit check\\n}\\n\\n\\n\\n\\n\\nWorking code\\u00a0(lib/parse.js:175):\\n\\nelse if (index \u003c= options.arrayLimit) { // Limit checked here\\n obj = [];\\n obj[index] = leaf;\\n}\\n\\n\\n\\n\\n\\nThe bracket notation handler at line 159 uses utils.combine([], leaf)\\u00a0without validating against options.arrayLimit, while indexed notation at line 175 checks index \u003c= options.arrayLimit\\u00a0before creating arrays.\\n\\nPoCTest 1 - Basic bypass:\\n\\nnpm install qs\\n\\n\\n\\n\\n\\nconst qs = require(\u0027qs\u0027);\\nconst result = qs.parse(\u0027a[]=1\u0026a[]=2\u0026a[]=3\u0026a[]=4\u0026a[]=5\u0026a[]=6\u0027, { arrayLimit: 5 });\\nconsole.log(result.a.length); // Output: 6 (should be max 5)\\n\\n\\n\\n\\n\\nTest 2 - DoS demonstration:\\n\\nconst qs = require(\u0027qs\u0027);\\nconst attack = \u0027a[]=\u0027 + Array(10000).fill(\u0027x\u0027).join(\u0027\u0026a[]=\u0027);\\nconst result = qs.parse(attack, { arrayLimit: 100 });\\nconsole.log(result.a.length); // Output: 10000 (should be max 100)\\n\\n\\n\\n\\n\\nConfiguration:\\n\\n * arrayLimit: 5\\u00a0(test 1) or arrayLimit: 100\\u00a0(test 2)\\n * Use bracket notation: a[]=value\\u00a0(not indexed a[0]=value)\\n\\n\\nImpactDenial of Service via memory exhaustion. Affects applications using qs.parse()\\u00a0with user-controlled input and arrayLimit\\u00a0for protection.\\n\\nAttack scenario:\\n\\n * Attacker sends HTTP request: GET /api/search?filters[]=x\u0026filters[]=x\u0026...\u0026filters[]=x\\u00a0(100,000+ times)\\n * Application parses with qs.parse(query, { arrayLimit: 100 })\\n * qs ignores limit, parses all 100,000 elements into array\\n * Server memory exhausted \\u2192 application crashes or becomes unresponsive\\n * Service unavailable for all users\\nReal-world impact:\\n\\n * Single malicious request can crash server\\n * No authentication required\\n * Easy to automate and scale\\n * Affects any endpoint parsing query strings with bracket notation\", \"supportingMedia\": [{\"type\": \"text/html\", \"value\": \"Improper Input Validation vulnerability in qs (parse modules) allows HTTP DoS.\u003cp\u003eThis issue affects qs: \u0026lt; 6.14.1.\u003c/p\u003e\u003ch3\u003e\u003cbr\u003eSummary\u003c/h3\u003e\u003cp\u003eThe \u003ccode\u003earrayLimit\u003c/code\u003e\u0026nbsp;option in qs does not enforce limits for bracket notation (\u003ccode\u003ea[]=1\u0026amp;a[]=2\u003c/code\u003e), allowing attackers to cause denial-of-service via memory exhaustion. Applications using \u003ccode\u003earrayLimit\u003c/code\u003e\u0026nbsp;for DoS protection are vulnerable.\u003c/p\u003e\u003ch3\u003eDetails\u003c/h3\u003e\u003cp\u003eThe \u003ccode\u003earrayLimit\u003c/code\u003e\u0026nbsp;option only checks limits for indexed notation (\u003ccode\u003ea[0]=1\u0026amp;a[1]=2\u003c/code\u003e) but completely bypasses it for bracket notation (\u003ccode\u003ea[]=1\u0026amp;a[]=2\u003c/code\u003e).\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eVulnerable code\u003c/strong\u003e\u0026nbsp;(\u003ccode\u003elib/parse.js:159-162\u003c/code\u003e):\u003c/p\u003e\u003cdiv\u003e\u003cpre\u003eif (root === \u0027[]\u0027 \u0026amp;\u0026amp; options.parseArrays) {\\n obj = utils.combine([], leaf); // No arrayLimit check\\n}\u003c/pre\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eWorking code\u003c/strong\u003e\u0026nbsp;(\u003ccode\u003elib/parse.js:175\u003c/code\u003e):\u003c/p\u003e\u003cdiv\u003e\u003cpre\u003eelse if (index \u0026lt;= options.arrayLimit) { // Limit checked here\\n obj = [];\\n obj[index] = leaf;\\n}\u003c/pre\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\u003cp\u003eThe bracket notation handler at line 159 uses \u003ccode\u003eutils.combine([], leaf)\u003c/code\u003e\u0026nbsp;without validating against \u003ccode\u003eoptions.arrayLimit\u003c/code\u003e, while indexed notation at line 175 checks \u003ccode\u003eindex \u0026lt;= options.arrayLimit\u003c/code\u003e\u0026nbsp;before creating arrays.\u003c/p\u003e\u003ch3\u003ePoC\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003eTest 1 - Basic bypass:\u003c/strong\u003e\u003c/p\u003e\u003cdiv\u003e\u003cpre\u003enpm install qs\u003c/pre\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\u003cdiv\u003e\u003cpre\u003econst qs = require(\u0027qs\u0027);\\nconst result = qs.parse(\u0027a[]=1\u0026amp;a[]=2\u0026amp;a[]=3\u0026amp;a[]=4\u0026amp;a[]=5\u0026amp;a[]=6\u0027, { arrayLimit: 5 });\\nconsole.log(result.a.length); // Output: 6 (should be max 5)\u003c/pre\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eTest 2 - DoS demonstration:\u003c/strong\u003e\u003c/p\u003e\u003cdiv\u003e\u003cpre\u003econst qs = require(\u0027qs\u0027);\\nconst attack = \u0027a[]=\u0027 + Array(10000).fill(\u0027x\u0027).join(\u0027\u0026amp;a[]=\u0027);\\nconst result = qs.parse(attack, { arrayLimit: 100 });\\nconsole.log(result.a.length); // Output: 10000 (should be max 100)\u003c/pre\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eConfiguration:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003earrayLimit: 5\u003c/code\u003e\u0026nbsp;(test 1) or \u003ccode\u003earrayLimit: 100\u003c/code\u003e\u0026nbsp;(test 2)\u003c/li\u003e\u003cli\u003eUse bracket notation: \u003ccode\u003ea[]=value\u003c/code\u003e\u0026nbsp;(not indexed \u003ccode\u003ea[0]=value\u003c/code\u003e)\u003c/li\u003e\u003c/ul\u003e\u003ch3\u003eImpact\u003c/h3\u003e\u003cp\u003eDenial of Service via memory exhaustion. Affects applications using \u003ccode\u003eqs.parse()\u003c/code\u003e\u0026nbsp;with user-controlled input and \u003ccode\u003earrayLimit\u003c/code\u003e\u0026nbsp;for protection.\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eAttack scenario:\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eAttacker sends HTTP request: \u003ccode\u003eGET /api/search?filters[]=x\u0026amp;filters[]=x\u0026amp;...\u0026amp;filters[]=x\u003c/code\u003e\u0026nbsp;(100,000+ times)\u003c/li\u003e\u003cli\u003eApplication parses with \u003ccode\u003eqs.parse(query, { arrayLimit: 100 })\u003c/code\u003e\u003c/li\u003e\u003cli\u003eqs ignores limit, parses all 100,000 elements into array\u003c/li\u003e\u003cli\u003eServer memory exhausted \\u2192 application crashes or becomes unresponsive\u003c/li\u003e\u003cli\u003eService unavailable for all users\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003eReal-world impact:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003eSingle malicious request can crash server\u003c/li\u003e\u003cli\u003eNo authentication required\u003c/li\u003e\u003cli\u003eEasy to automate and scale\u003c/li\u003e\u003cli\u003eAffects any endpoint parsing query strings with bracket notation\u003c/li\u003e\u003c/ul\u003e\", \"base64\": false}]}], \"problemTypes\": [{\"descriptions\": [{\"lang\": \"en\", \"type\": \"CWE\", \"cweId\": \"CWE-20\", \"description\": \"CWE-20 Improper Input Validation\"}]}], \"providerMetadata\": {\"orgId\": \"7ffcee3d-2c14-4c3e-b844-86c6a321a158\", \"shortName\": \"harborist\", \"dateUpdated\": \"2025-12-29T22:56:45.240Z\"}}}",
"cveMetadata": "{\"cveId\": \"CVE-2025-15284\", \"state\": \"PUBLISHED\", \"dateUpdated\": \"2025-12-30T15:57:41.402Z\", \"dateReserved\": \"2025-12-29T21:36:51.399Z\", \"assignerOrgId\": \"7ffcee3d-2c14-4c3e-b844-86c6a321a158\", \"datePublished\": \"2025-12-29T22:56:45.240Z\", \"assignerShortName\": \"harborist\"}",
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
}
}
Loading…
Loading…
Sightings
| Author | Source | Type | Date |
|---|
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.
Loading…
Loading…