Jun 15, 2026·7 min read·12 visits
The esbuild local development server on Windows is vulnerable to arbitrary file read due to a path traversal flaw caused by improper backslash normalization.
Improper validation of backslash character separators in esbuild's local development server allows path traversal on Windows systems.
The vulnerability designated as GHSA-G7R4-M6W7-QQQR exposes a path traversal flaw in the local development server of esbuild, a widely adopted JavaScript bundler and minifier. The flaw is specifically present when the development server is run on the Windows operating system. It allows an unauthenticated remote attacker to retrieve arbitrary files from the host filesystem that are accessible to the user running the esbuild process.
In modern web development workflows, developers utilize local servers to test, hot-reload, and debug their front-end applications. The esbuild tool provides a built-in development server via its API (the esbuild.serve() function) to host compiled assets and serve static directories. Because this server interacts directly with the local file system to locate and deliver files, rigorous input validation of HTTP request paths is essential to maintain the security boundary.
This vulnerability arises because the server fails to properly sanitize Windows-style backslash (\) path separators when checking if a requested asset lies within the designated root directory. Consequently, requests designed to traverse directory structures bypass the internal safety checks and map directly onto the underlying Windows file system APIs, which treat both forward slashes and backslashes as path separators.
To validate request paths, the esbuild development server relies on Go's standard library path package, specifically the path.Clean() function. This function is designed to normalize path strings by resolving relative segments (such as ., ..), removing duplicate separators, and cleaning trailing slashes. This normalized path is then concatenated with the server's designated serve directory to locate the requested file on disk.
The fundamental limitation of Go's path package is that it is designed strictly for Unix-style paths. It treats the forward slash (/) as the only valid path separator. When presented with a backslash (\), path.Clean() does not recognize it as a path boundary but treats it as a standard literal character. Therefore, path traversal payloads containing backslashes, such as /..\..\..\Windows\win.ini, bypass the normalization routine entirely.
Once the unsanitized path bypasses the Go path cleaning routine, the application passes the string to OS-level file system calls. On the Windows operating system, filesystem APIs natively accept both forward slashes and backslashes as valid directory separators. When the system API receives the unresolved traversal elements (..\), it moves up the directory tree relative to the serving root, culminating in access to absolute file locations across the entire drive volume.
The patch introduced in version 0.28.1 directly addresses the root cause by preventing any path containing a backslash from being handled by the server. Because the local development server only needs to serve files based on standard HTTP URL paths (which strictly use forward slashes), backslash characters are inherently invalid in legitimate incoming request paths.
The logic changes in the HTTP request handler filter out invalid characters before passing the path string to the cleanup functions. In the vulnerable version, the server accepted any request path and passed it directly to path.Clean:
// Vulnerable logic flow (representation)
func serveFile(w http.ResponseWriter, r *http.Request) {
// Request path is taken directly from the URL
reqPath := r.URL.Path
// path.Clean only cleans forward slashes. Backslashes remain untouched.
cleanedPath := path.Clean(reqPath)
// On Windows, os.Open resolves backslashes, triggering traversal
file, err := os.Open(filepath.Join(serveDir, cleanedPath))
// ...
}The remediated code implements a strict check that inspects the request path for the presence of backslash characters before executing any filesystem interactions. If a backslash is detected, the server immediately rejects the request with a standard bad request error or a localized 400/404 response. This simple but highly effective validation ensures that the Windows filesystem API is never forced to parse unsafe OS-specific separators:
// Patched logic flow (representation)
func serveFile(w http.ResponseWriter, r *http.Request) {
reqPath := r.URL.Path
// Explicit rejection of backslash characters to prevent Windows path traversal
if strings.Contains(reqPath, "\\") {
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
// Safe to clean and join as only forward slashes are present
cleanedPath := path.Clean(reqPath)
file, err := os.Open(filepath.Join(serveDir, cleanedPath))
// ...
}This remediation strategy is robust because it creates an absolute barrier against Windows path-delimiter trickery. By validating the input path at the boundary of the HTTP server, esbuild avoids having to implement complex, platform-dependent sanitization routines deep inside its core file-handling layers.
Exploitation of this vulnerability is straightforward and requires no active authentication. An attacker must construct an HTTP GET request targeting the running esbuild development server. The request URL must contain directory traversal sequences utilizing Windows backslash separators to escape the restricted directory.
For example, if the esbuild server is serving files from C:\projects\my-app\www, a standard request for /index.html resolves safely. However, a crafted request containing backslashes bypasses the path.Clean check and maps outside the folder structure:
GET /..\..\..\..\..\..\Windows\win.ini HTTP/1.1
Host: localhost:8000
Connection: closeWhen the esbuild server processes this request, the path is checked via the Unix-only path.Clean(). Finding no forward slashes in the traversal sequences, the path resolver treats the sequence ..\..\ as a single literal folder name, returning it as-is. When the file retrieval layer joins this with the serve directory (C:\projects\my-app\www\..\..\..\..\..\..\Windows\win.ini), the Windows operating system normalizes the sequence to C:\Windows\win.ini and returns the file contents to the client.
The security impact of GHSA-G7R4-M6W7-QQQR is rated as High, with a CVSS v3.1 base score of 7.5. Although the vulnerability does not lead to direct code execution or file modification, the confidentiality compromise is severe. An attacker can read any configuration files, application source code, local databases, or operating system configuration files that the running developer's process has permissions to read.
In typical local development workflows, esbuild runs with the privileges of the active developer. This means that any file accessible to the developer—including private SSH keys, .env files containing production credentials, browser session cookies, and sensitive documents—can be extracted by a remote actor who can route requests to the development server.
Furthermore, because the local development server may bind to all interfaces (0.0.0.0) by default or because of manual developer configuration, the server is frequently exposed to other hosts on the same local area network (LAN). This local exposure increases the threat vector from a purely local attacker to any compromised machine or malicious actor residing on the same subnet.
To remediate the vulnerability, users and developers must upgrade their esbuild installation to version 0.28.1 or later. This update is available through standard package managers such as npm or Deno's module resolution system. After upgrading, the server automatically rejects all path requests containing backslashes, closing the traversal vector entirely.
If upgrading immediately is not feasible, developers should implement defensive configuration measures. The most effective workaround is to ensure that the development server binds strictly to the local loopback interface (127.0.0.1 or ::1) rather than the wildcard interface (0.0.0.0). This prevents other devices on the same network from initiating connections to the vulnerable server.
Additionally, implementing a reverse proxy or utilizing firewall rules to block inbound TCP traffic to the esbuild server port can prevent unauthorized access. Organizations should also encourage developers to run development tools within containerized or sandboxed environments to isolate sensitive host directories from any potentially exposed development processes.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
esbuild evanw | < 0.28.1 | 0.28.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| Attack Vector | Network (HTTP) |
| CVSS v3.1 Score | 7.5 (High) |
| Exploit Status | PoC Available |
| Patch Version | 0.28.1 |
| Affected OS | Windows |
The software uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize sequences such as '..' that can resolve to a location outside of the directory.
An authentication bypass in the SiYuan personal knowledge management system before version 3.7.0 exposes a dynamic icon rendering endpoint. This endpoint processes client-supplied Go template directives. By submitting a crafted request, an unauthenticated remote attacker can leverage registered database template functions to execute arbitrary read-only SQL queries and exfiltrate workspace contents.
CVE-2026-54069 is a critical authentication bypass vulnerability in the SiYuan Note personal knowledge management system. The flaw is located in the HTTP server's middleware handling API authorization, which unconditionally trusts requests carrying a 'chrome-extension://' scheme in the Origin HTTP header, granting administrative access without validating API tokens.
CVE-2026-54089 is a critical authentication bypass vulnerability in File Browser affecting instances configured with proxy-based authentication. An unauthenticated remote attacker with direct network access can impersonate arbitrary users or register new accounts by spoofing configured HTTP headers.
The malicious Cargo package 'exploration' was uploaded to the crates.io registry. During compilation or package import, the crate executes code designed to establish an outbound TCP/HTTP connection, download an external second-stage binary, and execute the binary locally on the host machine. This creates an unauthenticated remote code execution vector impacting developer environments and continuous integration pipelines.
CVE-2026-54088 is a critical command injection vulnerability in File Browser prior to version 2.63.6. When Hook Authentication is enabled, the application interpolates unsanitized credentials into a shell command, allowing unauthenticated remote code execution.
An authenticated remote code execution vulnerability exists in NotrinosERP (versions up to and including 1.0.0) within the Human Resource Management (HRM) module. Users with employee management permissions can upload arbitrary file types, including PHP scripts, which are written directly to a web-accessible directory. This allows for arbitrary code execution in the context of the web-server user.