Is your feature request related to a problem? Please describe.
Add an explicit trust decision before an automatically discovered working-directory config can control executable launch settings. This is a defensive feature request. The tested behavior matches the documented config-discovery and custom-browser features; the available evidence does not establish a violated security contract or an ordinary behavioral bug.
The original security hypothesis remains unresolved because no supported workflow was established that accepts attacker-controlled project content while withholding host-launch authority from its configuration. The absence of a documented trust grant does not prove the opposite contract. This draft therefore proposes a new defensive control without claiming a confirmed vulnerability, observed compromise, or supported P1 defect.
When a user starts the server in a project directory, it automatically loads cd4a.config.json there if no explicit --config was supplied. The file can supply recognized launch options, including executablePath, unless explicit flags supersede or conflict with them. The CLI also discovers the file when a tool command automatically starts a new daemon. A user inspecting a project may want its files to remain data until the user explicitly trusts them to configure host process launch.
The configuration source is consequential. Source inspection confirms that the selected executable passes through BrowserManager and Puppeteer to Node's process-spawn API, with the server account's authority and inherited environment. Browser sandboxing and an isolated profile do not create a host-process trust decision before that spawn. If a project-selected executable satisfies the OS execution requirements, its host confidentiality and integrity effects are credible consequences of that launch authority. Those consequences were inferred from source, not observed by executing a replacement program.
The relevant prerequisites are startup in the project working directory, enabled discovery, no explicit trusted config superseding the file, compatible effective launch flags, an accessible executable meeting OS requirements, and a later browser-launching operation. CLI auto-start additionally requires no existing daemon for that scoped session. Cloning a repository, viewing a page, or receiving web content alone does not establish that launch path.
Describe the solution you'd like
Require a user-controlled trust or opt-in decision before a discovered working-directory file can supply executable launch settings. Apply the same decision to stdio server startup and CLI daemon auto-start. Until that decision exists, use trusted explicit configuration and launch flags, or fail before process creation with an actionable explanation.
Preserve custom-browser selection through user-selected trusted configuration and explicit launch flags. Preserve the documented precedence of explicit flags over the selected config file. The implementation may choose an opt-in for project discovery or a source-specific restriction on launch-sensitive options, provided the user-visible acceptance boundary below holds.
Show which configuration source was selected and whether it has launch authority. A diagnostic message alone does not satisfy the explicit-trust requirement.
- Starting either entry point in an untrusted fixture directory cannot let its discovered config select a host executable without an explicit trusted decision, even if the file has valid JSON and recognized keys.
- The same rule holds when a CLI tool command automatically starts its daemon with that working directory. Rejection, if chosen, occurs before spawning the project-selected process.
- Trusted custom-browser configuration still launches the intended installed browser. Explicit flags retain precedence over file values, and an explicit trusted
--config supersedes the working-directory file.
CHROME_DEVTOOLS_MCP_NO_CONFIG_DISCOVERY=1 continues to prevent implicit discovery while allowing explicit trusted configuration.
- The user can determine which config source was selected and whether project-local executable launch authority was granted. A prompt, if used, must fail closed in unattended operation rather than block indefinitely or implicitly approve.
- Regression coverage includes both real entry points, source selection, precedence, disabled discovery, and a positive trusted custom-browser case. A launch recorder can verify that untrusted settings cannot reach process creation without running a project-provided program. Benign headless isolated browser tests can verify wiring and workflow preservation.
These criteria define one independently closable capability. They do not require changing browser-download, source-map, extension, web-content, or tool-output behavior.
This draft does not remove intentional custom-browser support, establish a full OS sandbox, prevent all unsafe actions by a trusted client, or restrict the project's documented browser capabilities. It does not assert that every MCP client launches its server from untrusted working directories. It does not claim a host-execution consequence when all project content already has trusted launch authority.
No fix was implemented or fixed behavior observed. No replacement executable, real credential, user data, exfiltration, destructive action, persistence mechanism, or non-local test target was used for the retained proof. The report remains private; no issue, PR, advisory, or comment has been created.
Describe alternatives you've considered
- Require explicit opt-in for working-directory discovery. This creates a simple source-level trust decision but changes project-config convenience for existing users.
- Restrict executable launch settings in discovered project config until that source is trusted. This preserves project-level configuration convenience but requires a clear source-sensitive policy for launch-sensitive settings.
- Keep discovery unchanged and document the existing environment-variable opt-out, explicit trusted config, and selected-source diagnostics. This preserves compatibility and offers a practical current control, but it does not satisfy the proposed explicit-trust capability.
The preferred outcome is explicit trust before project-local executable launch authority. The first two approaches can satisfy it; the third is the verified current workaround for users who require that boundary, rather than completion of this feature.
Additional context
The verified config path includes src/config/ConfigLocator.ts, src/config/ConfigParser.ts, and src/config/browser-options.ts. The source distinction binds the proposed behavior because the parser currently handles explicitly chosen and implicitly discovered configuration through the same option validation and merge path. src/bin/chrome-devtools-mcp-main.ts, src/bin/chrome-devtools.ts, and src/daemon/client.ts are the relevant entry points; the daemon inherits the CLI working directory. src/BrowserManager.ts forwards launch options to Puppeteer. Both entry points must obey the same trust decision for this feature to be complete.
The tested source baseline was upstream main at commit 5ddb0a3110c5059f8e5513e566196cce2a35c6d1, obtained by a fresh clone and built with npm ci from the clone root and npm run build. Its version field still reports 1.10.1, so the commit identifies that build. The separately installed npm latest package was chrome-devtools-mcp 1.10.1, installed using npm --prefix; it did not discover the working-directory config. The observed environment was Node v22.23.2, npm 12.0.2, Chrome 154.0.8037.98, and macOS 27.0. The source build's installed puppeteer-core dependency was 25.12.0.
The configuration documentation explicitly describes discovery in the working directory before plugin and global configuration, first-file selection without merging, explicit config precedence, CLI flag precedence, and the discovery-disable variable. Merged PR #2876 deliberately introduced this behavior. The requested trust gate would add a restriction to that existing feature.
The security policy assigns input validation to the calling agent/client, identifies powerful browser operations as intentional features, and says suggestions for a more secure user experience are feature requests. It does not explicitly adjudicate this startup-config scenario. Together with the documented intended discovery behavior and the missing contrary trust contract, that supports the defensive-feature classification. The project directs actual security reports to the Google Open Source Software Vulnerability Reward Program. This draft is not a confirmed vulnerability report for that channel; no program eligibility or maintainer acceptance is claimed.
Fresh verification used disposable directories, task-local TMPDIR, XDG_CONFIG_HOME, and XDG_RUNTIME_DIR, no PLUGIN_DATA, update checks off, and usage statistics off. Retained MCP tests explicitly passed --headless --isolated --no-usage-statistics --no-performance-crux. The source-build CLI tests also used headless isolated browsers, checked in actual process arguments. Static marker pages were served only on 127.0.0.1 with OS-assigned unused ports, never port 8765.
The reduced fixture contained this harmless config:
{
"viewport": "713x419",
"headless": true,
"isolated": true,
"performanceCrux": false,
"usageStatistics": false
}
To repeat the benign observation, start the respective build/src/bin/chrome-devtools-mcp.js entry point from an empty working directory, initialize an ordinary stdio MCP session, and call list_pages. Serve a static page titled CWD discovery benign marker on a fresh loopback port. Call navigate_page with page ID 1 and that URL, then evaluate_script with page ID 1 and the function below. Close the session and repeat from the fixture directory without --config. Repeat again with discovery disabled, with --viewport=829x457, and with explicit trusted config outside the fixture containing {"viewport":"811x433"}. Use fresh processes and temporary browser profiles for each case.
() => ({marker: document.title, width: innerWidth, height: innerHeight})
| MCP case |
Source build |
Released package |
| Empty working directory |
1200×2029 |
1200×2029 |
| Fixture config, no explicit config |
713×419 |
1200×2029 |
| Fixture config, discovery disabled |
1200×2029 |
1200×2029 |
| Fixture config, explicit viewport |
829×457 |
829×457 |
| Fixture config, explicit trusted config |
811×433 |
811×433 |
All ten retained MCP cases returned the marker title with successful navigation and measurement. Default dimensions are observations of this environment, not a product guarantee. The input was actually reduced by removing the installed-browser executable setting and rerunning the cases; the viewport effect persisted with the displayed fixture.
For the source-build CLI, use a fresh daemon session identifier and task-local runtime directory. From the fixture directory, invoke list_pages with no existing daemon, then navigate_page 1 --url followed by the marker URL, and evaluate_script followed by the measurement function and --pageId 1. Stop the scoped daemon after measurement. Auto-start returned the marker title at 713×419. Repeating with discovery disabled returned 1200×2029. The recorded explicit daemon arguments were only --viaCli, which confirms that the viewport arrived through discovery. The released-package comparison above uses explicit isolated MCP runs; a released-CLI control that used a fresh reusable profile was discarded and that task-created profile was removed.
An additional harmless executable-setting case pointed executablePath at the installed Chrome binary. The built parser selected the working-directory config, retained that exact executable setting, left channel unset, and retained headless mode, isolation, and disabled usage statistics. Real Chrome launched successfully. Source inspection traced ConfigParser to BrowserManager, then puppeteer-core's launcher and @puppeteer/browsers' call to childProcess.spawn(). A path-existence check and OS execution requirements apply; no project-trust or browser-identity check was present in that inspected path. This supports the launch-control concern but does not establish the missing security contract.
Earlier supplied evidence included a marker script, a config selecting it, and target-close traces. No retained marker output was present. This investigation treated those as leads and did not count the handoff's claimed replacement-script execution as a freshly observed result. The retained proof uses harmless settings and installed Chrome only. The draft includes its material observations and does not depend on private raw logs.
The public corpus screen covered 2,360 open and closed GitHub issue/PR records on 2026-10-06: 103 open and 473 closed issues, plus 34 open and 1,750 closed PRs. Titles and bodies were screened for the config filename, config discovery, executable selection, and untrusted-project terms. Focused GitHub searches also covered indexed discussions; each returned incomplete_results=false. Relevant config PR reviews and comments were read. No public matching trust-control request or remediation was found in this bounded screen. Private reports and every historical comment cannot be covered by that statement.
PR #2868 and PR #2871 were closed without merging. Merged PR #2849 establishes explicit CLI precedence over file values. Open PR #2878 concerns optional config watching, rather than source trust. Issue #2388 requests persistent CLI defaults, a different outcome. The open release PR #2823 proposes 1.11.0; that is planned metadata, not a tested release or a guarantee this behavior will ship unchanged.
The current opt-out is practical and verified: place CHROME_DEVTOOLS_MCP_NO_CONFIG_DISCOVERY=1 in the trusted launch environment, and retain desired settings in explicit trusted configuration or flags. Disabling discovery preserved successful navigation and measurement in fresh MCP and source-build CLI runs. Explicit trusted config also superseded the fixture in both MCP builds.
Is your feature request related to a problem? Please describe.
Add an explicit trust decision before an automatically discovered working-directory config can control executable launch settings. This is a defensive feature request. The tested behavior matches the documented config-discovery and custom-browser features; the available evidence does not establish a violated security contract or an ordinary behavioral bug.
The original security hypothesis remains unresolved because no supported workflow was established that accepts attacker-controlled project content while withholding host-launch authority from its configuration. The absence of a documented trust grant does not prove the opposite contract. This draft therefore proposes a new defensive control without claiming a confirmed vulnerability, observed compromise, or supported P1 defect.
When a user starts the server in a project directory, it automatically loads
cd4a.config.jsonthere if no explicit--configwas supplied. The file can supply recognized launch options, includingexecutablePath, unless explicit flags supersede or conflict with them. The CLI also discovers the file when a tool command automatically starts a new daemon. A user inspecting a project may want its files to remain data until the user explicitly trusts them to configure host process launch.The configuration source is consequential. Source inspection confirms that the selected executable passes through
BrowserManagerand Puppeteer to Node's process-spawn API, with the server account's authority and inherited environment. Browser sandboxing and an isolated profile do not create a host-process trust decision before that spawn. If a project-selected executable satisfies the OS execution requirements, its host confidentiality and integrity effects are credible consequences of that launch authority. Those consequences were inferred from source, not observed by executing a replacement program.The relevant prerequisites are startup in the project working directory, enabled discovery, no explicit trusted config superseding the file, compatible effective launch flags, an accessible executable meeting OS requirements, and a later browser-launching operation. CLI auto-start additionally requires no existing daemon for that scoped session. Cloning a repository, viewing a page, or receiving web content alone does not establish that launch path.
Describe the solution you'd like
Require a user-controlled trust or opt-in decision before a discovered working-directory file can supply executable launch settings. Apply the same decision to stdio server startup and CLI daemon auto-start. Until that decision exists, use trusted explicit configuration and launch flags, or fail before process creation with an actionable explanation.
Preserve custom-browser selection through user-selected trusted configuration and explicit launch flags. Preserve the documented precedence of explicit flags over the selected config file. The implementation may choose an opt-in for project discovery or a source-specific restriction on launch-sensitive options, provided the user-visible acceptance boundary below holds.
Show which configuration source was selected and whether it has launch authority. A diagnostic message alone does not satisfy the explicit-trust requirement.
--configsupersedes the working-directory file.CHROME_DEVTOOLS_MCP_NO_CONFIG_DISCOVERY=1continues to prevent implicit discovery while allowing explicit trusted configuration.These criteria define one independently closable capability. They do not require changing browser-download, source-map, extension, web-content, or tool-output behavior.
This draft does not remove intentional custom-browser support, establish a full OS sandbox, prevent all unsafe actions by a trusted client, or restrict the project's documented browser capabilities. It does not assert that every MCP client launches its server from untrusted working directories. It does not claim a host-execution consequence when all project content already has trusted launch authority.
No fix was implemented or fixed behavior observed. No replacement executable, real credential, user data, exfiltration, destructive action, persistence mechanism, or non-local test target was used for the retained proof. The report remains private; no issue, PR, advisory, or comment has been created.
Describe alternatives you've considered
The preferred outcome is explicit trust before project-local executable launch authority. The first two approaches can satisfy it; the third is the verified current workaround for users who require that boundary, rather than completion of this feature.
Additional context
The verified config path includes
src/config/ConfigLocator.ts,src/config/ConfigParser.ts, andsrc/config/browser-options.ts. The source distinction binds the proposed behavior because the parser currently handles explicitly chosen and implicitly discovered configuration through the same option validation and merge path.src/bin/chrome-devtools-mcp-main.ts,src/bin/chrome-devtools.ts, andsrc/daemon/client.tsare the relevant entry points; the daemon inherits the CLI working directory.src/BrowserManager.tsforwards launch options to Puppeteer. Both entry points must obey the same trust decision for this feature to be complete.The tested source baseline was upstream
mainat commit5ddb0a3110c5059f8e5513e566196cce2a35c6d1, obtained by a fresh clone and built withnpm cifrom the clone root andnpm run build. Its version field still reports 1.10.1, so the commit identifies that build. The separately installed npmlatestpackage was chrome-devtools-mcp 1.10.1, installed usingnpm --prefix; it did not discover the working-directory config. The observed environment was Node v22.23.2, npm 12.0.2, Chrome 154.0.8037.98, and macOS 27.0. The source build's installed puppeteer-core dependency was 25.12.0.The configuration documentation explicitly describes discovery in the working directory before plugin and global configuration, first-file selection without merging, explicit config precedence, CLI flag precedence, and the discovery-disable variable. Merged PR #2876 deliberately introduced this behavior. The requested trust gate would add a restriction to that existing feature.
The security policy assigns input validation to the calling agent/client, identifies powerful browser operations as intentional features, and says suggestions for a more secure user experience are feature requests. It does not explicitly adjudicate this startup-config scenario. Together with the documented intended discovery behavior and the missing contrary trust contract, that supports the defensive-feature classification. The project directs actual security reports to the Google Open Source Software Vulnerability Reward Program. This draft is not a confirmed vulnerability report for that channel; no program eligibility or maintainer acceptance is claimed.
Fresh verification used disposable directories, task-local
TMPDIR,XDG_CONFIG_HOME, andXDG_RUNTIME_DIR, noPLUGIN_DATA, update checks off, and usage statistics off. Retained MCP tests explicitly passed--headless --isolated --no-usage-statistics --no-performance-crux. The source-build CLI tests also used headless isolated browsers, checked in actual process arguments. Static marker pages were served only on127.0.0.1with OS-assigned unused ports, never port 8765.The reduced fixture contained this harmless config:
{ "viewport": "713x419", "headless": true, "isolated": true, "performanceCrux": false, "usageStatistics": false }To repeat the benign observation, start the respective
build/src/bin/chrome-devtools-mcp.jsentry point from an empty working directory, initialize an ordinary stdio MCP session, and calllist_pages. Serve a static page titledCWD discovery benign markeron a fresh loopback port. Callnavigate_pagewith page ID 1 and that URL, thenevaluate_scriptwith page ID 1 and the function below. Close the session and repeat from the fixture directory without--config. Repeat again with discovery disabled, with--viewport=829x457, and with explicit trusted config outside the fixture containing{"viewport":"811x433"}. Use fresh processes and temporary browser profiles for each case.All ten retained MCP cases returned the marker title with successful navigation and measurement. Default dimensions are observations of this environment, not a product guarantee. The input was actually reduced by removing the installed-browser executable setting and rerunning the cases; the viewport effect persisted with the displayed fixture.
For the source-build CLI, use a fresh daemon session identifier and task-local runtime directory. From the fixture directory, invoke
list_pageswith no existing daemon, thennavigate_page 1 --urlfollowed by the marker URL, andevaluate_scriptfollowed by the measurement function and--pageId 1. Stop the scoped daemon after measurement. Auto-start returned the marker title at 713×419. Repeating with discovery disabled returned 1200×2029. The recorded explicit daemon arguments were only--viaCli, which confirms that the viewport arrived through discovery. The released-package comparison above uses explicit isolated MCP runs; a released-CLI control that used a fresh reusable profile was discarded and that task-created profile was removed.An additional harmless executable-setting case pointed
executablePathat the installed Chrome binary. The built parser selected the working-directory config, retained that exact executable setting, leftchannelunset, and retained headless mode, isolation, and disabled usage statistics. Real Chrome launched successfully. Source inspection tracedConfigParsertoBrowserManager, thenpuppeteer-core's launcher and@puppeteer/browsers' call tochildProcess.spawn(). A path-existence check and OS execution requirements apply; no project-trust or browser-identity check was present in that inspected path. This supports the launch-control concern but does not establish the missing security contract.Earlier supplied evidence included a marker script, a config selecting it, and target-close traces. No retained marker output was present. This investigation treated those as leads and did not count the handoff's claimed replacement-script execution as a freshly observed result. The retained proof uses harmless settings and installed Chrome only. The draft includes its material observations and does not depend on private raw logs.
The public corpus screen covered 2,360 open and closed GitHub issue/PR records on 2026-10-06: 103 open and 473 closed issues, plus 34 open and 1,750 closed PRs. Titles and bodies were screened for the config filename, config discovery, executable selection, and untrusted-project terms. Focused GitHub searches also covered indexed discussions; each returned
incomplete_results=false. Relevant config PR reviews and comments were read. No public matching trust-control request or remediation was found in this bounded screen. Private reports and every historical comment cannot be covered by that statement.PR #2868 and PR #2871 were closed without merging. Merged PR #2849 establishes explicit CLI precedence over file values. Open PR #2878 concerns optional config watching, rather than source trust. Issue #2388 requests persistent CLI defaults, a different outcome. The open release PR #2823 proposes 1.11.0; that is planned metadata, not a tested release or a guarantee this behavior will ship unchanged.
The current opt-out is practical and verified: place
CHROME_DEVTOOLS_MCP_NO_CONFIG_DISCOVERY=1in the trusted launch environment, and retain desired settings in explicit trusted configuration or flags. Disabling discovery preserved successful navigation and measurement in fresh MCP and source-build CLI runs. Explicit trusted config also superseded the fixture in both MCP builds.