# Risk map — webpack/webpack

> Canonical page: https://codevetter.com/unpack/webpack/risk-map

# Risk map — webpack/webpack

Scanned commit 87a62dec2304cd2c163c41feeeb43fbe3e5c21dd (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

webpack's real security surface is that it executes arbitrary third-party code by design — loaders, plugins and config files all run with full Node privileges in the developer's process — so the interesting risks are the paths that widen that, not the bundler core. Concretely: `HttpUriPlugin` fetches remote code over the network, `lazyCompilationBackend` opens a listening HTTP server, `CleanPlugin` deletes files, `DotenvPlugin` reads secrets into the bundle, and the cache deserializer reconstructs arbitrary registered classes from disk. Operationally, the largest fragility is size and coupling: `Compilation.js` is 6,724 lines with a seal pipeline whose phase ordering is load-bearing, the three `syntax-parser.js` files total ~46k lines with V8-inlining-budget constraints baked into specific methods, and several correctness properties (cache round-trip, generated-file freshness, deep-import compatibility) are enforced only by conventions that a careless edit silently violates.
- Arbitrary code execution is the design, not a bug: `loadLoader` requires loader modules from the resolved graph and `runLoaders` invokes them with a full loader context, so any dependency reachable as a loader runs with the developer's privileges — there is no sandbox in this path. — [lib/loaders/loadLoader.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/loaders/loadLoader.js) [lib/loaders/LoaderRunner.js#L528-580](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/loaders/LoaderRunner.js#L528-L580) [lib/loaders/LoaderRunner.js#L812-870](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/loaders/LoaderRunner.js#L812-L870)
- `HttpUriPlugin` is the highest-value security path: it fetches module source over `http:`/`https:`, routes through `options.proxy` or the `http_proxy`/`HTTP_PROXY` environment variables, and its `allowedUris` policy must be re-checked after every redirect — the redirect check at L773-790 is the control that stops an allowed host from redirecting to an arbitrary one. — [lib/schemes/HttpUriPlugin.js#L546-560](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/schemes/HttpUriPlugin.js#L546-L560) [lib/schemes/HttpUriPlugin.js#L773-790](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/schemes/HttpUriPlugin.js#L773-L790) [lib/schemes/HttpUriPlugin.js#L1095-1135](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/schemes/HttpUriPlugin.js#L1095-L1135)
- Fetched remote bodies are written to disk under `cacheLocation` (defaulting to `<lockfileLocation>.data`) keyed by a computed `key`, so a poisoned or unvalidated response becomes a persisted build input. — [lib/schemes/HttpUriPlugin.js#L573-600](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/schemes/HttpUriPlugin.js#L573-L600) [lib/schemes/HttpUriPlugin.js#L737-745](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/schemes/HttpUriPlugin.js#L737-L745) [lib/schemes/HttpUriPlugin.js#L1244-1270](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/schemes/HttpUriPlugin.js#L1244-L1270)
- `lazyCompilationBackend` binds a real HTTP/HTTPS listener in the dev process and keeps a `Set` of live sockets; its request handler mutates an `activeModules` refcount from client-supplied keys, so exposure of that port exposes compile triggers. — [lib/hmr/lazyCompilationBackend.js#L32-140](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/hmr/lazyCompilationBackend.js#L32-L140)
- `CleanPlugin` performs `unlink` and `rmdir` under `output.path` based on a filesystem diff, with `keep` (a `SyncBailHook` plus user matcher) and `dry` as the only brakes — a misconfigured `output.path` makes this a destructive operation on a directory the user did not intend. — [lib/output/CleanPlugin.js#L92-120](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/output/CleanPlugin.js#L92-L120) [lib/output/CleanPlugin.js#L180-340](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/output/CleanPlugin.js#L180-L340) [lib/output/CleanPlugin.js#L376-382](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/output/CleanPlugin.js#L376-L382)
- `DotenvPlugin` reads `.env`, `.env.local`, `.env.[mode]` and `.env.[mode].local` and feeds the parsed, `dotenv-expand`-expanded values into `DefinePlugin` — i.e. straight into the emitted bundle — so a missing `prefix` filter ships secrets to the browser. — [lib/define/DotenvPlugin.js#L55-65](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/define/DotenvPlugin.js#L55-L65) [lib/define/DotenvPlugin.js#L199-215](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/define/DotenvPlugin.js#L199-L215) [lib/define/EnvironmentPlugin.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/define/EnvironmentPlugin.js)
- The cache deserializer instantiates classes named by strings read off disk: `registerLoader(/^webpack\/lib\//, …)` maps a request to a loader in the generated `internalSerializables`, and an unknown request only produces a `console.warn` — a cache file is therefore a trusted input. — [lib/util/serialization.js#L25-50](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/util/serialization.js#L25-L50) [lib/serialization/ObjectMiddleware.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/serialization/ObjectMiddleware.js) [lib/cache/PackFileCacheStrategy.js#L1162-1180](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/cache/PackFileCacheStrategy.js#L1162-L1180)
- Deserialization re-enters constructors with no arguments, so a constructor that dereferences a parameter throws during restore and manifests only as a `Restoring failed for <identifier> from pack` debug line — a silent-by-default failure mode documented as a recurring trap. — [AGENTS.md](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/AGENTS.md) [lib/util/makeSerializable.js#L45-58](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/util/makeSerializable.js#L45-L58)
- Blast-radius hotspot #1 is `lib/Compilation.js` (6,724 lines): a single class owning the module graph, chunk graph, five async queues, the whole seal pipeline, asset emission and the hook surface — any reordering inside `seal` changes what plugins observe. — [lib/Compilation.js#L3612-3999](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/Compilation.js#L3612-L3999) [lib/Compilation.js#L4484-4530](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/Compilation.js#L4484-L4530) [lib/Compilation.js#L5174-5200](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/Compilation.js#L5174-L5200)
- Blast-radius hotspot #2 is the parser trio: `javascript/syntax-parser.js` (17,844 lines), `css/syntax-parser.js` (14,973) and `html/syntax-parser.js` (13,197), whose hot methods (`readWord`, `readString`, `finishToken`) are sized to fit V8's ~460-byte inlining budget — adding one argument to `readWord` once cost 1.4%. — [lib/javascript/syntax-parser.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/javascript/syntax-parser.js) [lib/css/syntax-parser.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/css/syntax-parser.js) [AGENTS.md](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/AGENTS.md)
- Fragile coupling: five `lib/*/data.js` modules and every `types.d.ts`/`declarations/*.d.ts`/`schemas/**/*.check.js` file are generated, and the `lint` job fails with only `… need to be updated` — a message that reads like a code problem even when the cause is a reworded JSDoc paragraph. — [lib/css/data.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/css/data.js) [lib/html/data.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/html/data.js) [lib/javascript/data.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/javascript/data.js) [package.json#L40-41](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/package.json#L40-L41) [AGENTS.md](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/AGENTS.md)
- Moving any file in `lib/` risks breaking the published ecosystem's deep imports; the only record of which paths are load-bearing is `tooling/deep-webpack-imports.json` (with `perKeyword`, `requests` and a `removed` map), checked by a CI job and mirrored by `test/unitCases/deepPathShims.unittest.js`. — [tooling/deep-webpack-imports.json](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/tooling/deep-webpack-imports.json) [tooling/find-deep-webpack-imports.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/tooling/find-deep-webpack-imports.js) [.github/workflows/deep-imports.yml](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/.github/workflows/deep-imports.yml)
- Legacy surface is explicit but live: `lib/wasm-sync/` is kept only until the next major, and `lib/index.js` re-exports `SingleEntryPlugin`, `LibraryTemplatePlugin`, `WebpackOptionsDefaulter` and `JavascriptModulesPlugin` behind `util.deprecate` with `DEP_WEBPACK_*` codes; root-level shims like `lib/NormalModule.js` (10 lines) exist purely as re-exports. — [lib/index.js#L315-330](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/index.js#L315-L330) [lib/index.js#L380-420](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/index.js#L380-L420) [lib/NormalModule.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/NormalModule.js) [lib/wasm-sync/](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/wasm-sync/)
- The Node 10.13 baseline is an under-enforced trap: `lib/` and `hot/` ship as raw source with no build step, and the baseline binds test fixtures too — a `configCases/` fixture using newer syntax passes locally and fails the Node 10 CI job with a bare `SyntaxError` inside the emitted bundle. — [AGENTS.md](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/AGENTS.md) [.github/workflows/test.yml#L579-645](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/.github/workflows/test.yml#L579-L645) [tsconfig.json#L2-4](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/tsconfig.json#L2-L4)
- Instance-shape discipline is a correctness-adjacent perf invariant enforced only by review: every field must be initialized in the constructor and never `delete`d, because a late first assignment forces a V8 hidden-class transition and deopts the inline caches on hot property reads. — [AGENTS.md](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/AGENTS.md) [lib/graph/Dependency.js](https://github.com/webpack/webpack/blob/87a62dec2304cd2c163c41feeeb43fbe3e5c21dd/lib/graph/Dependency.js)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
