mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-02 11:21:34 +00:00
fix(sandbox): reject and migrate browser network none (#115250)
* fix(sandbox): reject browser network none * test(ui): reset location after tools panel tests * chore(sandbox): drop release-owned changelog entry * fix(config): migrate unsupported sandbox browser network * fix(sandbox): isolate browser network constant * fix(config): preserve blank browser network overrides * chore: leave release changelog untouched
This commit is contained in:
@@ -923,7 +923,7 @@ Codex app-server turns in an active OpenClaw sandbox use this same egress settin
|
||||
noVNC observer access is password-protected and brokered through a one-time, authenticated bootstrap URL. The observer URL is deliberately omitted from model-visible system prompt context.
|
||||
|
||||
- `allowHostControl: false` (default) blocks sandboxed sessions from targeting the host browser.
|
||||
- `network` defaults to `openclaw-sandbox-browser` (dedicated bridge network). Set to `bridge` only when you explicitly want global bridge connectivity. `"host"` is blocked here too.
|
||||
- `network` defaults to `openclaw-sandbox-browser` (dedicated bridge network). Set to `bridge` only when you explicitly want global bridge connectivity. `"none"` is unsupported because CDP ports must be published to the host; `"host"` is blocked too. On upgrade, `openclaw doctor --fix` disables sidecars affected by a persisted `"none"` value and restores the dedicated network without silently enabling egress.
|
||||
- `cdpSourceRange` optionally restricts CDP ingress at the container edge to a CIDR range (for example `172.21.0.1/32`).
|
||||
- `sandbox.browser.binds` mounts additional host directories into the sandbox browser container only. When set (including `[]`), it replaces `docker.binds` for the browser container.
|
||||
- The sandbox browser container's Chromium always launches with `--no-sandbox --disable-setuid-sandbox` (containers do not have the kernel primitives Chrome's own sandbox needs); there is no config toggle for this.
|
||||
|
||||
@@ -133,6 +133,7 @@ On Ubuntu/AppArmor hosts with Docker sandbox mode enabled, Codex app-server `wor
|
||||
|
||||
- The sandbox browser auto-starts (ensures CDP is reachable) when the browser tool needs it. Configure via `agents.defaults.sandbox.browser.autoStart` (default `true`) and `autoStartTimeoutMs` (default 12s).
|
||||
- Sandbox browser containers use a dedicated Docker network (`openclaw-sandbox-browser`) instead of the global `bridge` network. Configure with `agents.defaults.sandbox.browser.network`.
|
||||
- Sandbox browser network mode `"none"` is unsupported because browser control requires host-published CDP ports. Use the dedicated default, `bridge`, or another custom bridge network. `openclaw doctor --fix` disables affected persisted sidecars and restores the dedicated network without silently enabling egress.
|
||||
- `agents.defaults.sandbox.browser.cdpSourceRange` restricts container-edge CDP ingress with a CIDR allowlist (for example `172.21.0.1/32`).
|
||||
- noVNC observer access is password-protected by default; OpenClaw emits a short-lived token URL that serves a local bootstrap page and opens noVNC with the password in the URL fragment (not query string or header logs).
|
||||
- `agents.defaults.sandbox.browser.allowHostControl` (default `false`) lets sandboxed sessions target the host browser explicitly.
|
||||
|
||||
1
src/agents/sandbox/browser-network.ts
Normal file
1
src/agents/sandbox/browser-network.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const DEFAULT_SANDBOX_BROWSER_NETWORK = "openclaw-sandbox-browser";
|
||||
@@ -1004,22 +1004,23 @@ describe("ensureSandboxBrowser create args", () => {
|
||||
expect(BROWSER_BRIDGES.get("session:test")).not.toBe(cached);
|
||||
});
|
||||
|
||||
it("does not inject a source range for network=none by default", async () => {
|
||||
it("rejects network=none before Docker inspection or browser bridge startup", async () => {
|
||||
const cfg = buildConfig(false);
|
||||
cfg.browser.network = "none";
|
||||
|
||||
const result = await ensureTestSandboxBrowser({
|
||||
scopeKey: "session:test",
|
||||
workspaceDir: "/tmp/workspace",
|
||||
agentWorkspaceDir: "/tmp/workspace",
|
||||
cfg,
|
||||
});
|
||||
|
||||
requireValue(result, "sandbox browser result");
|
||||
const createArgs = requireDockerCreateArgs();
|
||||
const envEntries = collectDockerFlagValues(createArgs, "-e");
|
||||
expect(envEntries.some((entry) => entry.startsWith("OPENCLAW_BROWSER_CDP_SOURCE_RANGE="))).toBe(
|
||||
false,
|
||||
await expect(
|
||||
ensureTestSandboxBrowser({
|
||||
scopeKey: "session:test",
|
||||
workspaceDir: "/tmp/workspace",
|
||||
agentWorkspaceDir: "/tmp/workspace",
|
||||
cfg,
|
||||
}),
|
||||
).rejects.toThrow(
|
||||
'Sandbox browser network mode "none" is unsupported because browser control requires a host-reachable published CDP port.',
|
||||
);
|
||||
expect(dockerMocks.dockerContainerState).not.toHaveBeenCalled();
|
||||
expect(dockerMocks.execDocker).not.toHaveBeenCalled();
|
||||
expect(dockerMocks.readDockerPort).not.toHaveBeenCalled();
|
||||
expect(bridgeMocks.startBrowserBridgeServer).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -235,6 +235,11 @@ export async function ensureSandboxBrowser(params: {
|
||||
if (!isToolAllowed(params.cfg.tools, "browser")) {
|
||||
return null;
|
||||
}
|
||||
if (normalizeOptionalLowercaseString(params.cfg.browser.network) === "none") {
|
||||
throw new Error(
|
||||
'Sandbox browser network mode "none" is unsupported because browser control requires a host-reachable published CDP port. Use "bridge", a custom bridge network, or disable the sandbox browser.',
|
||||
);
|
||||
}
|
||||
|
||||
const slug = params.cfg.scope === "shared" ? "shared" : slugifySessionKey(params.scopeKey);
|
||||
const name = `${params.cfg.browser.containerPrefix}${slug}`;
|
||||
|
||||
@@ -7,6 +7,8 @@ import path from "node:path";
|
||||
import { CHANNEL_IDS } from "../../channels/ids.js";
|
||||
import { STATE_DIR } from "../../config/paths.js";
|
||||
|
||||
export { DEFAULT_SANDBOX_BROWSER_NETWORK } from "./browser-network.js";
|
||||
|
||||
export const DEFAULT_SANDBOX_WORKSPACE_ROOT = path.join(STATE_DIR, "sandboxes");
|
||||
|
||||
export const DEFAULT_SANDBOX_IMAGE = "openclaw-sandbox:bookworm-slim";
|
||||
@@ -59,7 +61,6 @@ export const SANDBOX_BROWSER_IMAGE_CONTRACT_EPOCH = "2026-05-12-cdp-relay-auth";
|
||||
export const SANDBOX_DOCKER_CREATE_ARGS_EPOCH = "2026-07-10-init";
|
||||
|
||||
export const DEFAULT_SANDBOX_BROWSER_PREFIX = "openclaw-sbx-browser-";
|
||||
export const DEFAULT_SANDBOX_BROWSER_NETWORK = "openclaw-sandbox-browser";
|
||||
export const DEFAULT_SANDBOX_BROWSER_CDP_PORT = 9222;
|
||||
export const DEFAULT_SANDBOX_BROWSER_VNC_PORT = 5900;
|
||||
export const DEFAULT_SANDBOX_BROWSER_NOVNC_PORT = 6080;
|
||||
|
||||
@@ -2293,6 +2293,177 @@ describe("legacy migrate sandbox scope aliases", () => {
|
||||
expect(res.changes).toStrictEqual([]);
|
||||
expect(res.config).toBeNull();
|
||||
});
|
||||
|
||||
it("disables the default sandbox browser network without granting inherited egress", () => {
|
||||
const raw = {
|
||||
agents: {
|
||||
defaults: {
|
||||
sandbox: {
|
||||
browser: {
|
||||
enabled: true,
|
||||
network: " NONE ",
|
||||
autoStart: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
entries: {
|
||||
main: { default: true },
|
||||
inherited: {
|
||||
sandbox: {
|
||||
browser: {
|
||||
enabled: true,
|
||||
headless: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
isolated: {
|
||||
sandbox: {
|
||||
browser: {
|
||||
network: "isolated-browser-net",
|
||||
},
|
||||
},
|
||||
},
|
||||
blankEnabled: {
|
||||
sandbox: {
|
||||
browser: {
|
||||
enabled: true,
|
||||
network: " ",
|
||||
},
|
||||
},
|
||||
},
|
||||
blankInherited: {
|
||||
sandbox: {
|
||||
browser: {
|
||||
network: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(findLegacyConfigIssues(raw).map((issue) => issue.path)).toEqual([
|
||||
"agents.defaults.sandbox.browser.network",
|
||||
]);
|
||||
const res = migrateLegacyConfigForTest(raw);
|
||||
|
||||
expect(res.changes).toStrictEqual([
|
||||
'Disabled agents.entries.inherited.sandbox.browser because it inherited unsupported browser network "none".',
|
||||
"Set agents.entries.isolated.sandbox.browser.enabled to true to preserve its explicit supported network while disabling the unsupported default browser network.",
|
||||
"Set agents.entries.blankInherited.sandbox.browser.enabled to true to preserve its explicit supported network while disabling the unsupported default browser network.",
|
||||
'Disabled agents.defaults.sandbox.browser and moved its unsupported network "none" → "openclaw-sandbox-browser".',
|
||||
]);
|
||||
expect(res.config?.agents?.defaults?.sandbox?.browser).toEqual({
|
||||
enabled: false,
|
||||
network: "openclaw-sandbox-browser",
|
||||
autoStart: false,
|
||||
});
|
||||
expect(res.config?.agents?.entries?.inherited?.sandbox?.browser).toEqual({
|
||||
enabled: false,
|
||||
headless: true,
|
||||
});
|
||||
expect(res.config?.agents?.entries?.isolated?.sandbox?.browser).toEqual({
|
||||
enabled: true,
|
||||
network: "isolated-browser-net",
|
||||
});
|
||||
expect(res.config?.agents?.entries?.blankEnabled?.sandbox?.browser).toEqual({
|
||||
enabled: true,
|
||||
network: " ",
|
||||
});
|
||||
expect(res.config?.agents?.entries?.blankInherited?.sandbox?.browser).toEqual({
|
||||
enabled: true,
|
||||
network: "",
|
||||
});
|
||||
expect(migrateLegacyConfigForTest(res.config)).toEqual({ config: null, changes: [] });
|
||||
});
|
||||
|
||||
it("disables explicit per-agent network none in keyed rosters", () => {
|
||||
const raw = {
|
||||
agents: {
|
||||
entries: {
|
||||
main: {
|
||||
default: true,
|
||||
sandbox: {
|
||||
browser: {
|
||||
enabled: true,
|
||||
network: "none",
|
||||
headless: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(findLegacyConfigIssues(raw).map((issue) => issue.path)).toEqual(["agents.entries"]);
|
||||
const res = migrateLegacyConfigForTest(raw);
|
||||
|
||||
expect(res.changes).toStrictEqual([
|
||||
'Disabled agents.entries.main.sandbox.browser and moved its unsupported network "none" → "openclaw-sandbox-browser".',
|
||||
]);
|
||||
expect(res.config?.agents?.entries?.main?.sandbox?.browser).toEqual({
|
||||
enabled: false,
|
||||
network: "openclaw-sandbox-browser",
|
||||
headless: true,
|
||||
});
|
||||
expect(migrateLegacyConfigForTest(res.config)).toEqual({ config: null, changes: [] });
|
||||
});
|
||||
|
||||
it("disables explicit per-agent network none in legacy list rosters", () => {
|
||||
const raw = {
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "legacy",
|
||||
default: true,
|
||||
sandbox: {
|
||||
browser: {
|
||||
network: "NONE",
|
||||
autoStart: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
expect(findLegacyConfigIssues(raw)).toContainEqual({
|
||||
path: "agents.list",
|
||||
message: expect.stringContaining('sandbox.browser.network = "none"'),
|
||||
});
|
||||
const res = migrateLegacyConfigForTest(raw);
|
||||
|
||||
expect(res.changes).toStrictEqual([
|
||||
'Disabled agents.list.0.sandbox.browser and moved its unsupported network "none" → "openclaw-sandbox-browser".',
|
||||
]);
|
||||
expect(res.config?.agents?.entries?.legacy?.sandbox?.browser).toEqual({
|
||||
enabled: false,
|
||||
network: "openclaw-sandbox-browser",
|
||||
autoStart: false,
|
||||
});
|
||||
expect(migrateLegacyConfigForTest(res.config)).toEqual({ config: null, changes: [] });
|
||||
});
|
||||
|
||||
it("leaves supported sandbox browser networks unchanged", () => {
|
||||
const raw = {
|
||||
agents: {
|
||||
entries: {
|
||||
main: {
|
||||
default: true,
|
||||
sandbox: {
|
||||
browser: {
|
||||
enabled: true,
|
||||
network: "openclaw-sandbox-browser",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(findLegacyConfigIssues(raw)).toEqual([]);
|
||||
expect(migrateLegacyConfigForTest(raw)).toEqual({ config: null, changes: [] });
|
||||
});
|
||||
});
|
||||
|
||||
describe("legacy migrate MCP server type aliases", () => {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// Legacy runtime agent config migrations for memory, heartbeat, sandbox, and runtime policy keys.
|
||||
import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id";
|
||||
import { normalizeOptionalLowercaseString } from "@openclaw/normalization-core/string-coerce";
|
||||
import { uniqueStrings } from "@openclaw/normalization-core/string-normalization";
|
||||
import {
|
||||
isCanonicalToolProviderPolicyKey,
|
||||
normalizeToolProviderPolicyKey,
|
||||
} from "../../../agents/provider-tool-policy.js";
|
||||
import { DEFAULT_SANDBOX_BROWSER_NETWORK } from "../../../agents/sandbox/browser-network.js";
|
||||
import { isKnownCoreToolId } from "../../../agents/tool-catalog.js";
|
||||
import { isToolAllowedByPolicyName } from "../../../agents/tool-policy-match.js";
|
||||
import { resolveToolProfilePolicy } from "../../../agents/tool-policy-shared.js";
|
||||
@@ -168,6 +170,27 @@ const LEGACY_SANDBOX_SCOPE_RULES: LegacyConfigRule[] = [
|
||||
},
|
||||
];
|
||||
|
||||
const UNSUPPORTED_SANDBOX_BROWSER_NETWORK_RULES: LegacyConfigRule[] = [
|
||||
{
|
||||
path: ["agents", "defaults", "sandbox", "browser", "network"],
|
||||
message:
|
||||
'agents.defaults.sandbox.browser.network = "none" cannot expose the browser control port. Run "openclaw doctor --fix" to disable the sidecar and restore the dedicated browser network.',
|
||||
match: isUnsupportedSandboxBrowserNetwork,
|
||||
},
|
||||
{
|
||||
path: ["agents", "entries"],
|
||||
message:
|
||||
'agents.entries.*.sandbox.browser.network = "none" cannot expose the browser control port. Run "openclaw doctor --fix" to disable the affected sidecar and restore the dedicated browser network.',
|
||||
match: hasAgentEntriesUnsupportedSandboxBrowserNetwork,
|
||||
},
|
||||
{
|
||||
path: ["agents", "list"],
|
||||
message:
|
||||
'agents.list[].sandbox.browser.network = "none" cannot expose the browser control port. Run "openclaw doctor --fix" to disable the affected sidecar and restore the dedicated browser network.',
|
||||
match: hasAgentListUnsupportedSandboxBrowserNetwork,
|
||||
},
|
||||
];
|
||||
|
||||
const LEGACY_AGENT_RUNTIME_POLICY_RULES: LegacyConfigRule[] = [
|
||||
{
|
||||
path: ["agents", "defaults", "agentRuntime", "fallback"],
|
||||
@@ -562,6 +585,142 @@ function migrateLegacySandboxPerSession(
|
||||
delete sandbox.perSession;
|
||||
}
|
||||
|
||||
function getSandboxBrowserConfig(container: unknown): Record<string, unknown> | null {
|
||||
return getRecord(getRecord(getRecord(container)?.sandbox)?.browser);
|
||||
}
|
||||
|
||||
function isUnsupportedSandboxBrowserNetwork(value: unknown): boolean {
|
||||
return normalizeOptionalLowercaseString(value) === "none";
|
||||
}
|
||||
|
||||
function hasAgentEntriesUnsupportedSandboxBrowserNetwork(value: unknown): boolean {
|
||||
const entries = getRecord(value);
|
||||
return Boolean(
|
||||
entries &&
|
||||
Object.entries(entries).some(
|
||||
([agentId, agent]) =>
|
||||
!isBlockedObjectKey(agentId) &&
|
||||
isUnsupportedSandboxBrowserNetwork(getSandboxBrowserConfig(agent)?.network),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function hasAgentListUnsupportedSandboxBrowserNetwork(value: unknown): boolean {
|
||||
return (
|
||||
Array.isArray(value) &&
|
||||
value.some((agent) =>
|
||||
isUnsupportedSandboxBrowserNetwork(getSandboxBrowserConfig(agent)?.network),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function migrateExplicitUnsupportedSandboxBrowserNetwork(
|
||||
browser: Record<string, unknown>,
|
||||
pathLabel: string,
|
||||
changes: string[],
|
||||
): void {
|
||||
if (!isUnsupportedSandboxBrowserNetwork(browser.network)) {
|
||||
return;
|
||||
}
|
||||
browser.enabled = false;
|
||||
browser.network = DEFAULT_SANDBOX_BROWSER_NETWORK;
|
||||
changes.push(
|
||||
`Disabled ${pathLabel} and moved its unsupported network "none" → "${DEFAULT_SANDBOX_BROWSER_NETWORK}".`,
|
||||
);
|
||||
}
|
||||
|
||||
function migrateAgentBrowserInheritedFromUnsupportedDefault(params: {
|
||||
agent: unknown;
|
||||
pathLabel: string;
|
||||
defaultBrowserEnabled: boolean;
|
||||
changes: string[];
|
||||
}): void {
|
||||
const browser = getSandboxBrowserConfig(params.agent);
|
||||
if (!browser) {
|
||||
return;
|
||||
}
|
||||
const hasExplicitNetwork = typeof browser.network === "string";
|
||||
const network = normalizeOptionalLowercaseString(browser.network);
|
||||
if (network === "none") {
|
||||
migrateExplicitUnsupportedSandboxBrowserNetwork(browser, params.pathLabel, params.changes);
|
||||
return;
|
||||
}
|
||||
if (!hasExplicitNetwork && browser.enabled === true) {
|
||||
browser.enabled = false;
|
||||
params.changes.push(
|
||||
`Disabled ${params.pathLabel} because it inherited unsupported browser network "none".`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (hasExplicitNetwork && browser.enabled === undefined && params.defaultBrowserEnabled) {
|
||||
browser.enabled = true;
|
||||
params.changes.push(
|
||||
`Set ${params.pathLabel}.enabled to true to preserve its explicit supported network while disabling the unsupported default browser network.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function migrateUnsupportedSandboxBrowserNetworks(
|
||||
raw: Record<string, unknown>,
|
||||
changes: string[],
|
||||
): void {
|
||||
const agents = getRecord(raw.agents);
|
||||
const defaults = getRecord(agents?.defaults);
|
||||
const defaultBrowser = getSandboxBrowserConfig(defaults);
|
||||
const defaultNetworkUnsupported = isUnsupportedSandboxBrowserNetwork(defaultBrowser?.network);
|
||||
const defaultBrowserEnabled = defaultBrowser?.enabled === true;
|
||||
|
||||
const entries = getRecord(agents?.entries);
|
||||
if (entries) {
|
||||
for (const [agentId, agent] of Object.entries(entries)) {
|
||||
if (isBlockedObjectKey(agentId)) {
|
||||
continue;
|
||||
}
|
||||
const pathLabel = `agents.entries.${agentId}.sandbox.browser`;
|
||||
if (defaultNetworkUnsupported) {
|
||||
migrateAgentBrowserInheritedFromUnsupportedDefault({
|
||||
agent,
|
||||
pathLabel,
|
||||
defaultBrowserEnabled,
|
||||
changes,
|
||||
});
|
||||
} else {
|
||||
const browser = getSandboxBrowserConfig(agent);
|
||||
if (browser) {
|
||||
migrateExplicitUnsupportedSandboxBrowserNetwork(browser, pathLabel, changes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(agents?.list)) {
|
||||
for (const [index, agent] of agents.list.entries()) {
|
||||
const pathLabel = `agents.list.${index}.sandbox.browser`;
|
||||
if (defaultNetworkUnsupported) {
|
||||
migrateAgentBrowserInheritedFromUnsupportedDefault({
|
||||
agent,
|
||||
pathLabel,
|
||||
defaultBrowserEnabled,
|
||||
changes,
|
||||
});
|
||||
} else {
|
||||
const browser = getSandboxBrowserConfig(agent);
|
||||
if (browser) {
|
||||
migrateExplicitUnsupportedSandboxBrowserNetwork(browser, pathLabel, changes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultBrowser) {
|
||||
migrateExplicitUnsupportedSandboxBrowserNetwork(
|
||||
defaultBrowser,
|
||||
"agents.defaults.sandbox.browser",
|
||||
changes,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function removeLegacyAgentRuntimePolicy(
|
||||
container: Record<string, unknown>,
|
||||
pathLabel: string,
|
||||
@@ -1438,6 +1597,12 @@ export const LEGACY_CONFIG_MIGRATIONS_RUNTIME_AGENTS: LegacyConfigMigrationSpec[
|
||||
}
|
||||
},
|
||||
}),
|
||||
defineLegacyConfigMigration({
|
||||
id: "agents.sandbox.browser.network-none",
|
||||
describe: "Disable sandbox browser sidecars that use unsupported network mode none",
|
||||
legacyRules: UNSUPPORTED_SANDBOX_BROWSER_NETWORK_RULES,
|
||||
apply: migrateUnsupportedSandboxBrowserNetworks,
|
||||
}),
|
||||
defineLegacyConfigMigration({
|
||||
id: "memorySearch->memory.search",
|
||||
describe: "Move memory search config to its canonical memory owner",
|
||||
|
||||
@@ -159,9 +159,9 @@ export const RUNTIME_FIELD_HELP: Record<string, string> = {
|
||||
"Required by default for gateway access (unless using Tailscale Serve identity); required for non-loopback binds.",
|
||||
"gateway.auth.password": "Required for Tailscale funnel.",
|
||||
"agents.defaults.sandbox.browser.network":
|
||||
"Docker network for sandbox browser containers (default: openclaw-sandbox-browser). Avoid bridge if you need stricter isolation.",
|
||||
'Docker network for sandbox browser containers (default: openclaw-sandbox-browser). Use the dedicated default or a custom bridge network; "none" is unsupported because browser control requires published CDP ports.',
|
||||
"agents.entries.*.sandbox.browser.network":
|
||||
"Per-agent override for sandbox browser Docker network.",
|
||||
'Per-agent override for the sandbox browser Docker network. Use a bridge network; "none" is unsupported because browser control requires published CDP ports.',
|
||||
"agents.defaults.sandbox.docker.dangerouslyAllowContainerNamespaceJoin":
|
||||
"DANGEROUS break-glass override that allows sandbox Docker network mode container:<id>. This joins another container namespace and weakens sandbox isolation.",
|
||||
"agents.entries.*.sandbox.docker.dangerouslyAllowContainerNamespaceJoin":
|
||||
|
||||
Reference in New Issue
Block a user