Aug 18, 2026·7 min read·0 visits
The chrome-devtools-mcp server failed to resolve symbolic links physically during path validation, allowing directory traversal and unauthorized read/write access outside the workspace via local symlinks.
A workspace boundary bypass vulnerability exists in the Chrome DevTools for Agents (chrome-devtools-mcp) Model Context Protocol (MCP) server from version 0.24.0 up to 1.1.0. The vulnerability allows an agent or malicious workspace containing symbolic links to read or modify arbitrary files outside the configured project workspace root directory. This occurs because the path validation function resolves paths lexically rather than physically.
The Model Context Protocol (MCP) server implemented by the Chrome DevTools for Agents (chrome-devtools-mcp) allows AI coding agents to control and inspect local Chrome instances. To prevent unauthorized actions, the application implements workspace boundaries. These boundaries restrict agent access to a specified project workspace root directory.
From version 0.24.0 to 1.1.0, the server relies on the McpContext.validatePath() function to enforce these restrictions. This function verifies whether user-supplied file paths lie within the allowed workspace roots. The vulnerability arises because this function uses lexical path resolution instead of querying the physical disk layout.
This flaw exposes an attack surface where symbolic links (symlinks) placed inside the workspace are followed by downstream operations. Since the validation layer does not resolve symlinks but subsequent filesystem tasks do, boundary validation is bypassed. The severity is tracked under CVE-2026-53766, with a CVSS score of 6.1, representing an integrity and confidentiality risk to the local host.
The underlying flaw stems from a confusion between lexical path normalization and physical path resolution. In Node.js, path.resolve() performs string manipulation on the components of a path. It evaluates relative segments like . and .. to compute an absolute path, but it does not interact with the underlying operating system filesystem to resolve symbolic links.
When a client requests a file operation, McpContext.validatePath() normalizes the target path using path.resolve(). If the path contains a directory or file that is physically a symbolic link pointing to a location outside the workspace root, path.resolve() retains the path as if it were inside the workspace. The prefix check then compares the lexically resolved path with the root path and incorrectly permits access.
Once the validation step passes, the path is handed over to downstream APIs such as Puppeteer's file upload interface or local filesystem writers. These APIs interact directly with the operating system filesystem, which natively traverses symbolic links. This mismatch allows an agent to access or overwrite arbitrary files on the local filesystem, escaping the restricted workspace environment.
An inspection of the vulnerable implementation in src/McpContext.ts reveals how the validation check is performed. The lexical comparison evaluates if the absolute path starts with the workspace root directory:
// Vulnerable synchronous path validation
const absolutePath = path.resolve(filePath);
for (const root of roots) {
const rootPath = path.resolve(fileURLToPath(root.uri));
if (
absolutePath === rootPath ||
absolutePath.startsWith(rootPath + path.sep)
) {
return; // Validation succeeds
}
}To address this issue, commit 176eb695137d9c46a61e2d4d5571880c5145cf46 replaced the synchronous lexical check with an asynchronous canonicalization. The updated implementation uses fs.realpath to resolve symbolic links to their physical destinations before running the boundary checks. Additionally, it introduces a mechanism to climb the directory tree for non-existent files.
// Fixed path validation using physical realpath
const canonicalPath = await resolveCanonicalPath(filePath);
for (const root of roots) {
const rootPath = path.resolve(fileURLToPath(root.uri));
const canonicalRoot = await fsPromises.realpath(rootPath);
if (
canonicalPath === canonicalRoot ||
canonicalPath.startsWith(canonicalRoot + path.sep)
) {
allowed = true;
break;
}
}The utility function resolveCanonicalPath resolves the absolute path via fs.realpath. If the target does not exist (raising an ENOENT error), the code iteratively traverses the parent hierarchy using path.dirname until an existing ancestor is found. It then resolves that ancestor's real path and appends the non-existent relative segments to complete the canonical path verification.
Exploitation requires that an attacker have the ability to introduce a symbolic link inside a workspace directory that the victim loads. The primary exploit vectors include arbitrary file reads (confidentiality bypass) and arbitrary file writes (integrity bypass). The attack does not require advanced privileges or active user interaction once the MCP server is operating on the untrusted repository.
To perform an arbitrary file read, the attacker creates a symbolic link in the repository pointing to a target file on the host filesystem, such as the user's AWS credentials file. The attacker then triggers a file-reading tool call through the MCP protocol, referencing the symbolic link path. Since the path resolves lexically within the workspace, the server allows the action, and Puppeteer uploads the actual target file to the active browser instance.
For arbitrary file writes, tools that generate screenshots or heap snapshots can be targeted. If the output path is configured to go through a symlink, the application will write data to files outside the workspace. This can be used to overwrite system configurations, SSH authorized keys, or environment files, leading to persistent local access.
A critical evaluation of the official patch indicates that while it mitigates simple symlink traversals, it introduces architectural complexities that warrant inspection. The function resolveCanonicalPath begins by calling path.resolve(filePath). This initial lexical step can be manipulated if relative segments are mixed with symbolic links in downstream operations.
Specifically, if a workspace directory contains a symbolic link named symlink_to_out pointing to /etc, and the supplied path is /workspace/symlink_to_out/../escaped_file, the lexical helper path.resolve() resolves the path to /workspace/escaped_file before it reaches fs.realpath. The boundary check passes because /workspace/escaped_file resides inside the workspace root. However, the downstream client might execute the original string on the disk, resulting in a traversal through /etc and escaping the root.
Additionally, the patch operates under an asynchronous model where the path validation and the actual file access are distinct steps in the event loop. This split introduces a Time-of-Check to Time-of-Use (TOCTOU) race condition. A concurrent process could replace a verified folder path with a symbolic link in the split second between the call to validatePath and the subsequent filesystem invocation, allowing a workspace escape.
To completely resolve the vulnerability, users and developers must upgrade chrome-devtools-mcp to version 1.1.0 or higher. This update changes the validation logic to physically resolve paths prior to execution. If running in environments where automated updates are disabled, dependency constraints in package.json should be verified to ensure the package is pinned to a safe release.
For systems where immediate upgrades are not possible, several workarounds are recommended. Administrators should disable write operations or restrict the permissions of the user account running the MCP server. Restricting the process using containerization or operating system sandboxing mechanisms (such as Docker, AppArmor, or gVisor) ensures that even if a workspace escape occurs, the process cannot access sensitive host system resources.
Furthermore, developers building MCP tools should avoid executing file operations using raw, un-canonicalized strings. Once validation completes, the validated canonical path must be used for all downstream operations, rather than the original string provided by the user. This practice eliminates the lexical and physical path mismatch vector entirely.
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
chrome-devtools-mcp Google Chrome DevTools | >=0.24.0 <1.1.0 | 1.1.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 / CWE-59 |
| Attack Vector | Local |
| CVSS Score | 6.1 |
| EPSS Score | 0.00107 |
| Impact | High (Integrity) |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
The product uses external input to construct a pathname that is intended to identify a directory or file that is located within a restricted directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
A high-severity security vulnerability exists in 9Router, an AI router and token saver dashboard. When dashboard authentication features are disabled or left in default configurations, the application exposes administrative testing routines directly to the public internet. Unauthenticated network adversaries can exploit the OIDC configuration validation endpoint to initiate arbitrary HTTP requests, routing unauthorized traffic to local loops, adjacent container ports, and cloud resource metadata interfaces.
CVE-2026-64849 is a critical Server-Side Request Forgery (SSRF) vulnerability affecting MLflow tracking servers prior to version 3.15.0. It allows unauthenticated remote attackers to bypass outbound request destination filters using DNS rebinding or HTTP redirects. This exposure risks compromising sensitive cloud infrastructure metadata and internal microservices.
This technical report details a missing authorization vulnerability (CVE-2026-69146 / GHSA-3p64-6gvh-82v5) affecting the MLflow platform from version 3.13.0 to 3.15.0. When MLflow is configured with the built-in basic-auth plugin, authenticated users can bypass run-level UPDATE authorization checks, enabling unauthorized dataset and model lineage metadata injection.
MLflow prior to version 3.15.0 fails to perform proper authorization checks when registering model versions, allowing authenticated users with access to a registered model to link and access artifacts from runs and models belonging to other users without authorization.
A high-severity Regular Expression Denial of Service (ReDoS) vulnerability in the sqlparse Python library prior to version 0.6.0 allows unauthenticated remote attackers to trigger CPU exhaustion and application denial of service via crafted SQL inputs containing unmatched dollar-quoted literals or unclosed multiline comments.
A high-severity logic inversion flaw in the uniget CLI completely bypasses Sigstore cryptographic signature verification on metadata files by default. If an attacker can poison the package metadata cache or repository, they can execute arbitrary OS commands under the privileges of the active user.