GHSA-g7r4-m6w7-qqqr

Suggest an improvement
Source
https://github.com/advisories/GHSA-g7r4-m6w7-qqqr
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-g7r4-m6w7-qqqr/GHSA-g7r4-m6w7-qqqr.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-g7r4-m6w7-qqqr
Downstream
CGA (8)
MINI (4)
Published
2026-06-12T20:08:53Z
Modified
2026-09-10T03:50:49Z
Severity
  • 2.5 (Low) CVSS_V3 - CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N CVSS Calculator
Summary
esbuild allows arbitrary file read when running the development server on Windows
Details

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:

// 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:

// 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

// 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
Database specific
{
    "cwe_ids":  [
        "CWE-22"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-06-12T20:08:53Z",
    "nvd_published_at":  null,
    "severity":  "LOW"
}
References

Affected packages

npm / esbuild

Package

Affected ranges

Type
SEMVER
Events
Introduced
0.27.3
Fixed
0.28.1

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-g7r4-m6w7-qqqr/GHSA-g7r4-m6w7-qqqr.json"