Introduction
The chrome.debugger API gives Chrome extensions access to the Chrome DevTools Protocol (CDP). It can be used to inspect network activity, debug JavaScript, interact with the DOM and CSS, and perform other browser-level debugging tasks.
That power also makes chrome.debugger different from many normal extension APIs. Because it can provide capabilities such as script evaluation and network interception, enterprise administrators may need stronger controls around extensions that use it.
Chrome 155 introduces stricter enforcement of enterprise policies for extensions using chrome.debugger. The change primarily affects extensions running in managed enterprise browsers where administrators have configured specific host restrictions, screenshot restrictions, or Data Loss Prevention (DLP) policies. Unmanaged browsers are not affected by this change.
For extension developers, the important change is that chrome.debugger.attach() can now fail before the extension establishes a debugging session.
This means an extension that works correctly on a developer's personal Chrome installation can behave differently inside an organization's managed browser environment.
What Is chrome.debugger?
The chrome.debugger API provides an extension-friendly transport for the Chrome DevTools Protocol.
A typical extension declares the permission in its manifest:
{
"manifest_version": 3,
"name": "Browser Diagnostics",
"version": "1.0.0",
"permissions": [
"debugger"
],
"background": {
"service_worker": "background.js"
}
}
The extension can then attach to a tab:
chrome.debugger.attach(
{ tabId: tabId },
"1.3",
() => {
if (chrome.runtime.lastError) {
console.error(
"Debugger attach failed:",
chrome.runtime.lastError.message
);
return;
}
console.log("Debugger attached");
}
);
Once attached, the extension can send CDP commands:
chrome.debugger.sendCommand(
{ tabId: tabId },
"Runtime.enable",
{},
() => {
if (chrome.runtime.lastError) {
console.error(
"Command failed:",
chrome.runtime.lastError.message
);
return;
}
console.log("Runtime domain enabled");
}
);
The debugger permission is required for this API and is not one of the permissions that can be requested as an optional permission.
What Changes in Chrome 155?
The important change is enterprise policy enforcement at debugger attachment time.
Chrome 155 introduces an all-or-nothing approach for certain enterprise restrictions. If the relevant policy applies, chrome.debugger.attach() is rejected rather than allowing the extension to establish a partially restricted debugging session.
There are two main cases developers need to understand.
Host Restrictions
If an enterprise administrator configures runtime_blocked_hosts for an extension through ExtensionSettings, chrome.debugger.attach() is blocked for all targets.
The important detail is that adding individual origins to runtime_allowed_hosts does not override this restriction for chrome.debugger.
The resulting error is:
Host access is restricted by policy.
This is different from a normal host-permission problem where an extension may simply need additional permission for a particular origin.
Screenshot and DLP Restrictions
Chrome 155 also considers enterprise restrictions related to screenshot capture and Data Loss Prevention.
If screenshot capture is disabled through an enterprise policy such as DisableScreenshots, or DLP rules restrict the target, chrome.debugger.attach() can fail.
The reported error is:
Screenshot capture is restricted by policy.
Again, the restriction is evaluated when the debugger is attached.
Why Does Chrome Apply the Restriction at attach()?
The distinction matters because chrome.debugger operates below the normal web-platform origin security model.
An extension using CDP can access powerful debugging functionality, including operations that are not equivalent to simply injecting a content script into an allowed website.
For example, a debugger session can interact with protocol domains such as:
chrome.debugger.sendCommand(
{ tabId },
"Network.enable"
);
or:
chrome.debugger.sendCommand(
{ tabId },
"Runtime.enable"
);
The security model therefore cannot simply treat every CDP operation as an ordinary page-level API.
Chrome's approach in 155 is to validate relevant enterprise restrictions when the extension attempts to attach. If the policy prevents debugger access, the session is rejected instead of being established and selectively restricted later.
Who Is Actually Affected?
This is an important distinction.
The Chrome 155 change does not mean every extension using chrome.debugger will suddenly stop working.
The affected environment looks more like this:
Chrome 155
|
+-- Unmanaged browser
| |
| +-- chrome.debugger continues normally
|
+-- Managed browser
|
+-- No relevant restriction
| |
| +-- chrome.debugger continues normally
|
+-- runtime_blocked_hosts
| |
| +-- debugger attach blocked
|
+-- Screenshot/DLP restriction
|
+-- debugger attach blocked
Chrome's documentation explicitly states that unmanaged browsers and managed environments without these specific restrictions continue to operate normally.
This means the biggest compatibility risk is usually not visible during ordinary local development.
Why Local Testing Can Miss the Problem
Imagine an extension is developed on a personal laptop.
The developer tests:
Chrome
↓
Extension
↓
chrome.debugger.attach()
↓
Success
The extension is then deployed to an organization where Chrome is centrally managed:
Managed Chrome
↓
Enterprise ExtensionSettings
↓
runtime_blocked_hosts
↓
chrome.debugger.attach()
↓
Failure
The extension code has not changed.
The browser environment has.
This is why extension testing should include at least one managed-browser scenario when chrome.debugger is a core dependency.
Handle attach() Failures Explicitly
One of the most important changes developers can make is to stop assuming that attach() always succeeds.
A fragile implementation might look like this:
chrome.debugger.attach(
{ tabId },
"1.3",
() => {
startDebugging(tabId);
}
);
If the attachment fails, startDebugging() should not execute.
A safer implementation is:
chrome.debugger.attach(
{ tabId },
"1.3",
() => {
const error = chrome.runtime.lastError;
if (error) {
console.error(
`Unable to attach debugger: ${error.message}`
);
notifyUser(
"Debugger access is unavailable in this browser."
);
return;
}
startDebugging(tabId);
}
);
The exact user-facing behavior depends on the extension.
A diagnostics tool might show a configuration message. A testing tool might disable the debugging feature. A developer extension might simply log the failure.
The important part is that the failure becomes an expected state rather than an uncaught condition.
Build Around Capability Detection
Extensions using chrome.debugger should think in terms of capabilities rather than assumptions.
For example:
async function startDebugger(tabId) {
return new Promise((resolve, reject) => {
chrome.debugger.attach(
{ tabId },
"1.3",
() => {
const error = chrome.runtime.lastError;
if (error) {
reject(new Error(error.message));
return;
}
resolve();
}
);
});
}
The calling code can then decide what to do:
try {
await startDebugger(tabId);
console.log("Debugger available");
await initializeProtocol(tabId);
} catch (error) {
console.error("Debugger unavailable:", error);
showDebuggerUnavailableMessage();
}
This is preferable to allowing a failed attachment to cascade into later CDP errors.
Do Not Confuse Host Permissions With Debugger Availability
Chrome extensions have several different permission concepts.
For example:
{
"permissions": [
"debugger",
"tabs"
]
}
and:
{
"host_permissions": [
"https://example.com/*"
]
}
serve different purposes.
A developer may see an origin listed in host_permissions and assume that the extension can therefore use chrome.debugger against that origin.
Enterprise policy can still block debugger attachment.
In Chrome 155, a configured runtime_blocked_hosts policy takes precedence over the assumption that a specific allowed origin is sufficient for debugger access.
Therefore, debugging an enterprise deployment requires checking both:
Extension permissions.
Browser management policies.
Should You Replace chrome.debugger?
Not automatically.
The correct question is whether the extension really needs CDP-level capabilities.
Chrome itself recommends considering higher-level APIs when direct CDP access is not required. Examples include chrome.scripting, chrome.declarativeNetRequest, and chrome.cookies, depending on the task.
For example, if an extension only needs to inject JavaScript into a permitted page, chrome.scripting may be more appropriate than using the debugger protocol.
If the extension needs to modify or block network requests according to predefined rules, chrome.declarativeNetRequest may provide a more focused API.
The architectural principle is simple:
Need CDP-level debugging?
|
Yes
|
Use chrome.debugger
Need only page scripting?
|
Yes
|
Use chrome.scripting
Need declarative request filtering?
|
Yes
|
Use chrome.declarativeNetRequest
Using a narrower API can reduce the dependency on debugger-level permissions and make enterprise deployment easier to manage.
What About Existing Extensions?
If an existing extension depends heavily on chrome.debugger, perform an environment audit before Chrome 155 reaches stable rollout.
Check:
Manifest
Confirm that the extension explicitly declares:
"permissions": [
"debugger"
]
Attachment Code
Find every call to:
chrome.debugger.attach()
and verify that failures are handled.
CDP Dependencies
Identify the protocol domains the extension actually uses:
Runtime
Network
Page
DOM
Debugger
Performance
This helps determine whether the debugger permission is genuinely required.
Enterprise Policies
Work with the organization's Chrome administrator to determine whether the extension is affected by:
runtime_blocked_hosts
DisableScreenshots
DLP policies
Do not assume that a successful local test represents a managed deployment.
Troubleshooting Chrome 155 Failures
If an extension suddenly reports that debugger attachment fails, work through the following sequence.
Step 1: Capture the Exact Error
Do not replace the original error with a generic message during development.
Record:
const error = chrome.runtime.lastError;
if (error) {
console.error(error.message);
}
Step 2: Check Whether the Browser Is Managed
The failure may occur only in an enterprise-managed browser.
Compare:
Personal Chrome
vs.
Managed Chrome
Step 3: Check Enterprise Policies
Look specifically for host restrictions, screenshot policies, and DLP configuration.
Step 4: Test the Same Extension in a Controlled Environment
If possible, reproduce the organization's policy configuration in a test environment.
Step 5: Determine Whether CDP Is Actually Necessary
If the extension only uses a small subset of capabilities that another extension API supports, consider moving away from chrome.debugger.
Temporary Development Workaround
Chrome's documentation describes a temporary command-line flag that can restore the pre-Chrome 155 behavior:
--disable-features=ExtensionDebuggerStrictPolicyRestrictions
However, this should be treated as a development or migration workaround, not as a production architecture.
Chrome states that this temporary flag is scheduled to be removed in Chrome 160.
If an organization depends on the flag, that is a signal that the extension or enterprise policy configuration needs to be reviewed rather than permanently relying on the workaround.
Chrome 155 Rollout Timeline
Chrome 155 entered the Beta channel on September 16, 2026.
The stable rollout is scheduled to begin on October 6, 2026.
That gives extension teams a useful testing window.
If your extension is distributed inside managed organizations and relies on chrome.debugger, test before the stable rollout rather than waiting for users to report failures.
Common Mistakes
Assuming chrome.debugger Always Works
The permission in the manifest does not guarantee that enterprise policy will allow a debugger session.
Ignoring chrome.runtime.lastError
A failed attach() must be handled explicitly.
Testing Only on Personal Chrome
This can hide enterprise-policy compatibility problems.
Assuming runtime_allowed_hosts Fixes Everything
For the Chrome 155 policy described here, a configured runtime_blocked_hosts list can block debugger attachment even when specific origins are listed as allowed.
Replacing chrome.debugger Without Reviewing Requirements
A higher-level API is useful only if it provides the capabilities your extension actually needs.
Using the Chrome 155 Workaround as a Permanent Fix
The temporary feature flag has a defined lifetime and is scheduled for removal in Chrome 160.
Best Practices
For extensions that depend on chrome.debugger, use the following approach:
Treat debugger attachment as a fallible operation.
Log the exact attachment error during development.
Test on managed Chrome, not only personal Chrome.
Coordinate with enterprise administrators before deployment.
Check
runtime_blocked_hosts, screenshot restrictions, and DLP policies.Use the narrowest extension API that satisfies the requirement.
Keep CDP-specific functionality isolated behind a small abstraction layer.
Provide a useful fallback when debugger access is unavailable.
Test Chrome Beta releases before major production rollouts.
Do not depend on temporary browser flags for the long term.
Production Checklist
Before deploying a Chrome extension that uses chrome.debugger, verify:
The
"debugger"permission is declared.Every
chrome.debugger.attach()call handles failure.chrome.runtime.lastErroris checked.The extension has been tested on a managed browser.
Enterprise
ExtensionSettingshave been reviewed.runtime_blocked_hostshas been checked.Screenshot and DLP restrictions have been reviewed.
The extension's actual CDP requirements are documented.
Higher-level APIs have been evaluated where appropriate.
Users receive a useful message when debugger access is unavailable.
Chrome 155 compatibility has been tested before stable rollout.
Summary
Chrome 155 does not remove or generally disable the chrome.debugger API. The change is more specific: Chrome is enforcing certain enterprise restrictions more strictly when an extension attempts to attach a debugger.
On managed browsers, configured runtime_blocked_hosts policies can cause chrome.debugger.attach() to fail for all targets, while screenshot and DLP restrictions can also prevent attachment. Unmanaged browsers and enterprise environments without these specific restrictions continue to work normally.
For extension developers, the main lesson is to treat debugger access as an environment-dependent capability.
If your extension needs full CDP access, test its behavior under enterprise policies and handle attach() failures cleanly. If it only needs a narrower capability, consider whether APIs such as chrome.scripting or chrome.declarativeNetRequest provide a better fit.
The Chrome 155 change is therefore less about rewriting every debugger-based extension and more about making enterprise policy behavior an explicit part of extension compatibility testing.

Join the conversation! Your thoughts help the community grow.