Track vulnerabilities like this one. Sign up free to get alerted when software you use is affected.
2.5

esbuild allows arbitrary file read on Windows development server

published 4 months ago
Summary

A vulnerability in esbuild's development server on Windows allows attackers to access files outside the intended directory. This is because the server does not correctly handle Windows path separators. To fix this, update to a version of esbuild that addresses this issue.

What to do
  • Update GitHub Actions esbuild to version 0.28.1.
Affected software
Ecosystem VendorProductAffected versions
npm GitHub Actions esbuild >= 0.27.3, < 0.28.1
Fix: upgrade to 0.28.1
Original advisory text
esbuild allows arbitrary file read when running the development server on Windows
### 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
Fix within
Internet-facing 60 days
Internal At next upgrade
  • Not known to be exploited
  • Needs hands-on effort to exploit (estimated)
  • Gives an attacker partial control (estimated)
Severity
2.5 Low
Type
CWE-22Path Traversal
Timeline
Published12 Jun 2026
Updated12 Jun 2026
First seen12 Jun 2026
Sources
Track software like this
Free during beta