Every CVE Search/ Get API key

CVE-2026-53766

chrome-devtools-mcp: validatePath() does not canonicalize symlinks before enforcing roots

6.1 MediumFix available

Chrome DevTools for agents (chrome-devtools-mcp) lets your coding agent control and inspect a live Chrome browser. From 0.24.0 until 1.1.0, McpContext.validatePath() enforces workspace roots by checking whether path.resolve(filePath) textually falls under one of the configured root paths. path.resolve() does not canonicalize symbolic links. As a result, a symlink inside a configured workspace root can point to a file outside that root, pass validation, and then be followed by downstream file read/write operations. This bypass applies even when the MCP client correctly declares the roots capability with a non-empty list. It is separate from the documented legacy behavior where missing roots capability allows all paths. The practical impact is a workspace-boundary bypass. In the write direction, filePath-writing tools can overwrite out-of-root files through an in-root symlink. In the read direction, upload_file can read through the symlink and send the file to the currently selected web page. This vulnerability is fixed in 1.1.0.

Attack profile

How easy it is to exploit

Attack vector
Local
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
High
Availability
Low

Exploit likelihood

0.12%Unchanged since Jun 25, 2026
90%50%10%1%

What each source reports

CVE List Score used 6.1

chrome-devtools-mcp: validatePath() does not canonicalize symlinks before enforcing roots

Chrome DevTools for agents (chrome-devtools-mcp) lets your coding agent control and inspect a live Chrome browser. From 0.24.0 until 1.1.0, McpContext.validatePath() enforces workspace roots by checking whether path.resolve(filePath) textually falls under one of the configured root paths. path.resolve() does not canonicalize symbolic links. As a result, a symlink inside a configured workspace root can point to a file outside that root, pass validation, and then be followed by downstream file read/write operations. This bypass applies even when the MCP client correctly declares the roots capability with a non-empty list. It is separate from the documented legacy behavior where missing roots capability allows all paths. The practical impact is a workspace-boundary bypass. In the write direction, filePath-writing tools can overwrite out-of-root files through an in-root symlink. In the read direction, upload_file can read through the symlink and send the file to the currently selected web page. This vulnerability is fixed in 1.1.0.

Record
CVE-2026-53766
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Weakness
CWE-22, CWE-59
Updated
2026-11-02
EUVDEUVD-2026-39104 6.1

Chrome DevTools for agents (chrome-devtools-mcp) lets your coding agent control and inspect a live Chrome browser. From 0.24.0 until 1.1.0, McpContext.validatePath() enforces workspace roots by checking whether path.resolve(filePath) textually falls under one of the configured root paths. path.resolve() does not canonicalize symbolic links. As a result, a symlink inside a configured workspace root can point to a file outside that root, pass validation, and then be followed by downstream file read/write operations. This bypass applies even when the MCP client correctly declares the roots capability with a non-empty list. It is separate from the documented legacy behavior where missing roots capability allows all paths. The practical impact is a workspace-boundary bypass. In the write direction, filePath-writing tools can overwrite out-of-root files through an in-root symlink. In the read direction, upload_file can read through the symlink and send the file to the currently selected web page. This vulnerability is fixed in 1.1.0.

Record
EUVD-2026-39104
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Updated
2026-11-02
GitHub AdvisoriesGHSA-8qf9-62x2-82pp 6.1

chrome-devtools-mcp: validatePath() does not canonicalize symlinks before enforcing roots

Summary

I originally reported this through Google Bug Hunters. The Google Bug Hunters team said this is in OSS VRP scope but not reward-eligible due to the project tier, and asked me to file an issue or PR directly with this repository. I am reporting it privately here first because it is an unfixed security issue.

McpContext.validatePath() enforces workspace roots by checking whether path.resolve(filePath) textually falls under one of the configured root paths. path.resolve() does not canonicalize symbolic links. As a result, a symlink inside a configured workspace root can point to a file outside that root, pass validation, and then be followed by downstream file read/write operations.

This bypass applies even when the MCP client correctly declares the roots capability with a non-empty list. It is separate from the documented legacy behavior where missing roots capability allows all paths.

The practical impact is a workspace-boundary bypass. In the write direction, filePath-writing tools can overwrite out-of-root files through an in-root symlink. In the read direction, upload_file can read through the symlink and send the file to the currently selected web page.

Details

Affected code:

src/McpContext.ts:178-199

validatePath(filePath?: string): void {
  if (filePath === undefined) {
    return;
  }
  const roots = this.roots();
  if (roots === undefined) {
    return;
  }
  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;
    }
  }
  throw new Error(
    `Access denied: path ${filePath} is not within any of the workspace roots ${JSON.stringify(roots)}.`,
  );
}

path.resolve() only normalizes path text such as . and ... It does not call realpath() and does not resolve symlinks. Therefore, a path like:

/workspace/project/cache/profile

can textually pass the /workspace prefix check even when cache/profile is a symlink to:

/home/user/.aws/credentials

Downstream consumers then perform real filesystem operations without O_NOFOLLOW:

  • src/McpContext.ts:720-738 saveFile() uses fs.mkdir({recursive: true}) and fs.writeFile().
  • src/tools/input.ts:454-497 upload_file calls puppeteer.uploadFile(filePath) or fileChooser.accept([filePath]).
  • Other filePath-writing tools include screenshots, heap snapshots, network response save paths, snapshots, screencasts, Lighthouse output, and performance trace saves.

This is not a TOCTOU/race condition. The symlink exists before validation and the PoC uses a single process. The issue is a canonicalization bypass / improper link resolution.

Preconditions:

  • The MCP client declares roots and supplies at least one workspace root.
  • A symlink exists inside the workspace and points outside the workspace.
  • For the remote prompt-injection chain, the user processes untrusted page content while chrome-devtools-mcp is connected.

A remote attacker does not need local access if a suitable workspace-internal symlink already exists, or if another trusted tool/workflow can create it. Without such a symlink, the issue is a local/workspace-state-dependent boundary bypass.

PoC

Conceptual exploitation with a configured root:

Configured roots:
  file:///workspace

Workspace path:
  /workspace/project/cache/profile -> /home/user/.aws/credentials

Tool call:
  upload_file({
    filePath: "/workspace/project/cache/profile",
    uid: "<file input element on current page>"
  })

Result:
  validatePath() accepts the path because it textually starts with /workspace.
  Puppeteer follows the symlink and uploads the target file to the page.

Lab-only PoC that replicates the exact validation logic and subsequent write. It writes only inside a fresh temporary directory and touches no system paths:

Record
GHSA-8qf9-62x2-82pp
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Weakness
CWE-22, CWE-59
Updated
2026-11-02
NVD 6.1

Chrome DevTools for agents (chrome-devtools-mcp) lets your coding agent control and inspect a live Chrome browser. From 0.24.0 until 1.1.0, McpContext.validatePath() enforces workspace roots by checking whether path.resolve(filePath) textually falls under one of the configured root paths. path.resolve() does not canonicalize symbolic links. As a result, a symlink inside a configured workspace root can point to a file outside that root, pass validation, and then be followed by downstream file read/write operations. This bypass applies even when the MCP client correctly declares the roots capability with a non-empty list. It is separate from the documented legacy behavior where missing roots capability allows all paths. The practical impact is a workspace-boundary bypass. In the write direction, filePath-writing tools can overwrite out-of-root files through an in-root symlink. In the read direction, upload_file can read through the symlink and send the file to the currently selected web page. This vulnerability is fixed in 1.1.0.

Record
CVE-2026-53766
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Weakness
CWE-22, CWE-59
Updated
2026-11-02
OSV 6.1

chrome-devtools-mcp: validatePath() does not canonicalize symlinks before enforcing roots

Chrome DevTools for agents (chrome-devtools-mcp) lets your coding agent control and inspect a live Chrome browser. From 0.24.0 until 1.1.0, McpContext.validatePath() enforces workspace roots by checking whether path.resolve(filePath) textually falls under one of the configured root paths. path.resolve() does not canonicalize symbolic links. As a result, a symlink inside a configured workspace root can point to a file outside that root, pass validation, and then be followed by downstream file read/write operations. This bypass applies even when the MCP client correctly declares the roots capability with a non-empty list. It is separate from the documented legacy behavior where missing roots capability allows all paths. The practical impact is a workspace-boundary bypass. In the write direction, filePath-writing tools can overwrite out-of-root files through an in-root symlink. In the read direction, upload_file can read through the symlink and send the file to the currently selected web page. This vulnerability is fixed in 1.1.0.

Record
CVE-2026-53766
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Weakness
CWE-22, CWE-59
Updated
2026-11-02
OSVGHSA-8qf9-62x2-82pp 6.1

chrome-devtools-mcp: validatePath() does not canonicalize symlinks before enforcing roots

Summary

I originally reported this through Google Bug Hunters. The Google Bug Hunters team said this is in OSS VRP scope but not reward-eligible due to the project tier, and asked me to file an issue or PR directly with this repository. I am reporting it privately here first because it is an unfixed security issue.

McpContext.validatePath() enforces workspace roots by checking whether path.resolve(filePath) textually falls under one of the configured root paths. path.resolve() does not canonicalize symbolic links. As a result, a symlink inside a configured workspace root can point to a file outside that root, pass validation, and then be followed by downstream file read/write operations.

This bypass applies even when the MCP client correctly declares the roots capability with a non-empty list. It is separate from the documented legacy behavior where missing roots capability allows all paths.

The practical impact is a workspace-boundary bypass. In the write direction, filePath-writing tools can overwrite out-of-root files through an in-root symlink. In the read direction, upload_file can read through the symlink and send the file to the currently selected web page.

Details

Affected code:

src/McpContext.ts:178-199

validatePath(filePath?: string): void {
  if (filePath === undefined) {
    return;
  }
  const roots = this.roots();
  if (roots === undefined) {
    return;
  }
  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;
    }
  }
  throw new Error(
    `Access denied: path ${filePath} is not within any of the workspace roots ${JSON.stringify(roots)}.`,
  );
}

path.resolve() only normalizes path text such as . and ... It does not call realpath() and does not resolve symlinks. Therefore, a path like:

/workspace/project/cache/profile

can textually pass the /workspace prefix check even when cache/profile is a symlink to:

/home/user/.aws/credentials

Downstream consumers then perform real filesystem operations without O_NOFOLLOW:

  • src/McpContext.ts:720-738 saveFile() uses fs.mkdir({recursive: true}) and fs.writeFile().
  • src/tools/input.ts:454-497 upload_file calls puppeteer.uploadFile(filePath) or fileChooser.accept([filePath]).
  • Other filePath-writing tools include screenshots, heap snapshots, network response save paths, snapshots, screencasts, Lighthouse output, and performance trace saves.

This is not a TOCTOU/race condition. The symlink exists before validation and the PoC uses a single process. The issue is a canonicalization bypass / improper link resolution.

Preconditions:

  • The MCP client declares roots and supplies at least one workspace root.
  • A symlink exists inside the workspace and points outside the workspace.
  • For the remote prompt-injection chain, the user processes untrusted page content while chrome-devtools-mcp is connected.

A remote attacker does not need local access if a suitable workspace-internal symlink already exists, or if another trusted tool/workflow can create it. Without such a symlink, the issue is a local/workspace-state-dependent boundary bypass.

PoC

Conceptual exploitation with a configured root:

Configured roots:
  file:///workspace

Workspace path:
  /workspace/project/cache/profile -> /home/user/.aws/credentials

Tool call:
  upload_file({
    filePath: "/workspace/project/cache/profile",
    uid: "<file input element on current page>"
  })

Result:
  validatePath() accepts the path because it textually starts with /workspace.
  Puppeteer follows the symlink and uploads the target file to the page.

Lab-only PoC that replicates the exact validation logic and subsequent write. It writes only inside a fresh temporary directory and touches no system paths:

Record
GHSA-8qf9-62x2-82pp
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L
Weakness
CWE-22, CWE-59
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
chrome-devtools-mcp
npm
0.24.0 to 1.0.1
1.1.0
chrome-devtools-mcp
npm
0.24.0 up to 1.1.0
1.1.0

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-53766 is a medium vulnerability (CVSS 6.1) in Chromedevtools Chrome-devtools-mcp, published June 24, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.12%, the 1st percentile. Fixed in chrome-devtools-mcp 1.1.0.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open