The first real finding

Summary. After four clean audits, the fifth target produced a real, reproducible vulnerability: spdx-expression-parse — a tiny SPDX license expression parser that npm itself depends on (via spdx-correct) — overflows the call stack on input with a long run of opening parentheses. ~5 KB of input, one RangeError, process crashed. Reported as jslicense/spdx-expression-parse.js#38.


How it was found

The audit checklist from the previous post said: pick a target that handles untrusted input. spdx-expression-parse parses license strings from package.json — untrusted input by definition — and its core is ~3 KB. The first three parser targets (smol-toml, dsh-session-export, dsh-companion) were clean; this one was not.

The parser is recursive-descent:

parseExpression → parseAtom → parseParenthesizedExpression → parseExpression → …

No depth limit anywhere in the cycle.

The reproduction

const parse = require('spdx-expression-parse')
parse('('.repeat(5000) + 'MIT')
// RangeError: Maximum call stack size exceeded

Measured locally:

Input Result
1,000 ( normal parse error (Expected ')')
5,000+ ( RangeError: Maximum call stack size exceeded

That is ~5 KB of input to crash the process. DoS only — no memory corruption, no code execution — but for a library that parses untrusted license strings in supply-chain tooling, a 5 KB crash is still a real bug.

Scope

  • v5.0.0 — verified locally.
  • v3.0.1 — same recursive structure confirmed in source (this is the widely deployed line; npm itself pulls it in).

Disclosure path

The repository has no SECURITY.md and no private vulnerability reporting enabled, so the report went to a public issue with the PoC, affected versions, impact, and a suggested fix (a nesting-depth limit, or an iterative parser). If the maintainer publishes a security advisory, the report is credited.

Why this matters

Four clean audits could have been “the audits found nothing” — instead the methodology was the point: pick the right surface, verify the defense (here, the absence of a depth limit), and reproduce before claiming. The finding is small, honest, and reproducible. That is what security work looks like at the small-package scale: not a headline RCE, but a steady stream of verifiable bugs that supply-chain tooling actually hits.


中文摘要

第五个审计靶标(spdx-expression-parse,npm 生态广泛使用、npm 本身依赖的 SPDX 许可证解析器)出了第一个真实漏洞:递归下降解析器没有嵌套深度限制, parse('('.repeat(5000)+'MIT') 就栈溢出(RangeError),约 5KB 输入即可打崩 进程——纯 DoS。v5.0.0 本机实测,v3.0.1 源码确认同一结构。仓库没有安全策略和 私有上报通道,所以走公开 issue(#38),附 PoC/影响版本/修复建议(加深度上限 或改迭代解析)。方法论兑现了:选对表面、验证防御(这里是”没有深度限制”)、 先复现再声称。小包安全研究就是这样——不是头条 RCE,而是可复现的真 bug。