
cjs-module-lexer 2.2.0 removes eval. That matters.
I’ve watched “dev-only” dependencies turn into real incidents in CI. This release strips eval out of cjs-module-lexer’s string parsing path.
What actually changed (not the marketing version)
Here’s the concrete bit. PR #118 replaces eval-based string decoding with an explicit string literal scanner.
- Eval went away: The lexer no longer relies on (0, eval)(str) to interpret string literals during parsing. It now scans the source text and decodes escapes itself.
- The public API stayed put: You still call parse(source). Integrators should not need to change call sites.
- Tests got stricter: The project runs tests with NODE_OPTIONS=–disallow-code-generation-from-strings, which would have broken the old eval path.
Security impact: why I treat this as a real upgrade
Eval in a parser makes me nervous. Not because every use explodes, but because build systems ingest code you did not write.
If your CI builds pull in third-party packages, you already run untrusted input through tooling. Removing eval closes off an entire class of “code generation from strings” problems, and it also plays nicer with locked-down environments that disallow it.
If your security team ever asked “can we run builds with codegen-from-strings disabled?”, this release makes that question easier.
Am I even using cjs-module-lexer?
This part trips people up. You almost never depend on this directly.
- npm: Run npm ls cjs-module-lexer to see who pulls it in, and whether your lockfile pins an older version.
- yarn: Run yarn why cjs-module-lexer to find the parent dependency that drags it into your tree.
- pnpm: Run pnpm why cjs-module-lexer and note which workspace depends on it, because monorepos love hiding this stuff.
How I’d upgrade it (including the annoying transitive case)
Upgrade it in staging first. Do not “just bump and ship” if your CI handles secrets.
- Direct dependency: Install cjs-module-lexer@2.2.0, commit the lockfile, then run your full build and test pipeline.
- Transitive dependency: Add an override so your tree actually picks up 2.2.0. npm uses overrides, Yarn uses resolutions, pnpm uses overrides too.
- Verify the lockfile: After install, re-run npm ls cjs-module-lexer (or your yarn/pnpm equivalent). I’ve seen “successful installs” that changed nothing.
What to test after the bump
Run the boring stuff. Then run one targeted check.
At minimum, rebuild whatever generates bundles in your pipeline and make sure it finishes without new warnings. If you can, run one CI job with NODE_OPTIONS=–disallow-code-generation-from-strings to catch tooling that still sneaks in eval somewhere else.
- Build smoke test: Clean install, clean build, then run the smallest “build and start” command you trust.
- Cache reset: Blow away bundler caches once. I hate this advice, but lexer output changes can stick in caches in weird ways.
- Rollback plan: If something breaks, pin the prior working version in your overrides and re-run the pipeline. Do not guess.
Known issues
The GitHub release notes do not list known issues for 2.2.0. That does not mean nobody hit a bug. It means nobody wrote it down.
Other stuff in this release: more tests, some script hardening, the usual.
Source links (so you can audit it)
Check the official tag and the PR that did the work. You should not trust my summary more than the diff.
- GitHub release: https://github.com/nodejs/cjs-module-lexer/releases/tag/2.2.0
- PR #118 (eval removal): https://github.com/nodejs/cjs-module-lexer/pull/118
Anyway.