Summary
| Attribute |
Value |
| Vendor / Org |
7rulnik (source-map-js fork) |
| Product |
source-map-js |
| Component |
lib/source-map-consumer.js (indexed-map section parsing) + lib/source-node.js (fromStringWithSourceMap) |
| Affected Versions |
>= 1.0.0, <= 1.2.1 (unfixed on main) |
| Severity |
High |
| CVSS 3.1 Score |
7.5 (High) |
| CVSS 3.1 Vector |
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| CWE |
CWE-1287 (Improper Validation of Specified Type of Input); also CWE-835 (Loop with Unreachable Exit Condition) |
| Affected File |
lib/source-map-consumer.js (section offset intake), lib/source-node.js:112-118 |
Description
An indexed source map ({ "sections": [...] }) carries a per-section offset.line. When such a
consumer is fed to SourceNode.fromStringWithSourceMap, the section offset is applied by a
line-padding loop in source-node.js that pushes one newline per line up to the mapping's generated
line. offset.line is never validated to be a bounded, non-negative integer against the actual
generated content. A crafted offset.line of 1e999 (which JSON.parse yields as Infinity), or a
merely very large finite value, forces this loop to run for an attacker-chosen number of iterations.
A large finite value blocks the Node event loop for that entire duration (a synchronous freeze); an
Infinity value drives the internal array length past the engine's limit and throws
RangeError: Invalid array length. The attacker converts a tiny indexed-map document into a
process-level stall or crash of any service that re-emits the map.
Impact
A service that re-emits untrusted indexed source maps (bundler merge step, symbolication worker)
freezes its event loop for an attacker-chosen duration or crashes with an uncatchable-in-place array
error. On a shared multi-tenant symbolication or build service, one crafted map denies service to the
other tenants whose work that process also serves.
Remediation
Recommended Fix
Validate offset.line and offset.column at section-intake time: require finite, non-negative
integers within a sane bound relative to the generated content, and throw a typed error otherwise.
Independently, cap or guard the line-padding loop in source-node.js so it cannot iterate beyond the
real generated-line count.
Workaround
Run re-emit in a child process with a wall-clock timeout and restart policy; reject indexed maps whose
sections[].offset.line is non-integer or exceeds a small bound.
References
Summary
lib/source-map-consumer.js(indexed-map section parsing) +lib/source-node.js(fromStringWithSourceMap)>= 1.0.0, <= 1.2.1(unfixed onmain)CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:Hlib/source-map-consumer.js(sectionoffsetintake),lib/source-node.js:112-118Description
An indexed source map (
{ "sections": [...] }) carries a per-sectionoffset.line. When such aconsumer is fed to
SourceNode.fromStringWithSourceMap, the section offset is applied by aline-padding loop in
source-node.jsthat pushes one newline per line up to the mapping's generatedline.
offset.lineis never validated to be a bounded, non-negative integer against the actualgenerated content. A crafted
offset.lineof1e999(whichJSON.parseyields asInfinity), or amerely very large finite value, forces this loop to run for an attacker-chosen number of iterations.
A large finite value blocks the Node event loop for that entire duration (a synchronous freeze); an
Infinityvalue drives the internal array length past the engine's limit and throwsRangeError: Invalid array length. The attacker converts a tiny indexed-map document into aprocess-level stall or crash of any service that re-emits the map.
Impact
A service that re-emits untrusted indexed source maps (bundler merge step, symbolication worker)
freezes its event loop for an attacker-chosen duration or crashes with an uncatchable-in-place array
error. On a shared multi-tenant symbolication or build service, one crafted map denies service to the
other tenants whose work that process also serves.
Remediation
Recommended Fix
Validate
offset.lineandoffset.columnat section-intake time: require finite, non-negativeintegers within a sane bound relative to the generated content, and throw a typed error otherwise.
Independently, cap or guard the line-padding loop in
source-node.jsso it cannot iterate beyond thereal generated-line count.
Workaround
Run re-emit in a child process with a wall-clock timeout and restart policy; reject indexed maps whose
sections[].offset.lineis non-integer or exceeds a small bound.References
lib/source-node.js:112-118, indexed-map section intake inlib/source-map-consumer.js(source-map-js 1.2.1)