Jun 15, 2026·7 min read·2 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 authenticated backend user with access to the Recycler module in TYPO3 CMS can bypass write restrictions and restore soft-deleted records on pages or database tables they are not authorized to modify. This vulnerability resides in the core DataHandler class due to missing permission checks during 'undelete' operations.
CVE-2026-11607 is a critical broken access control vulnerability in TYPO3 CMS's Form Framework (ext:form). Authenticated backend users with access to the Form Framework can load unauthorized YAML configurations, bypassing file extension restrictions. This allows the execution of arbitrary SQL commands via the SaveToDatabase finisher, leading to privilege escalation to administrator level.
An issue was discovered in the Deno integration of the esbuild package. The module fails to verify the integrity of downloaded native binary packages from NPM registries before writing and executing them on the local filesystem. This allows an attacker who controls the NPM_CONFIG_REGISTRY environment variable or intercepts the network connection to execute arbitrary native code on the host machine.
A thread-safety vulnerability exists in the PyO3 library versions prior to 0.29.0 due to a missing Sync trait bound on closure type parameters. This omission allows safe Rust code to register non-thread-safe closures as Python callables, leading to concurrent shared mutation and data races during multithreaded execution.
A denial of service vulnerability in the ConnectBot SSH Client Library (cbssh) up to version 0.3.0 allows remote attackers to cause uncontrolled resource consumption. The library uses Kaitai Struct to parse incoming binary streams, but failed to validate the declared length of SSH fields against the physical stream size, leading to excessive memory allocation and OutOfMemoryError crashes.
An integer overflow and excessive memory allocation vulnerability in the Distinguished Encoding Rules (DER) private-key parser of ConnectBot SSH Client Library (connectbot/cbssh) allows a local attacker to cause a Denial of Service (DoS) via process termination. By inducing an application utilizing the library to parse a malformed DER-encoded private key file, the library attempts massive memory allocations, triggering an uncaught OutOfMemoryError on the JVM.