惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
Martin Fowler
Martin Fowler
MongoDB | Blog
MongoDB | Blog
Engineering at Meta
Engineering at Meta
Stack Overflow Blog
Stack Overflow Blog
Google DeepMind News
Google DeepMind News
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
I
InfoQ
B
Blog
WordPress大学
WordPress大学
Jina AI
Jina AI
小众软件
小众软件
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园_首页
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
酷 壳 – CoolShell
酷 壳 – CoolShell
阮一峰的网络日志
阮一峰的网络日志
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
Google Developers Blog
C
Check Point Blog
月光博客
月光博客
L
LangChain Blog
GbyAI
GbyAI

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix(security): audit Claude permission overrides under YO...
sallyom · 2026-05-26 · via Recent Commits to openclaw:main
11

import path from "node:path";

22

import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";

3+

import { resolveExecDefaults } from "../agents/exec-defaults.js";

4+

import { normalizeProviderId } from "../agents/provider-id.js";

35

import { resolveSandboxConfigForAgent } from "../agents/sandbox/config.js";

46

import type { ChannelPlugin } from "../channels/plugins/types.plugin.js";

57

import type { ConfigFileSnapshot, OpenClawConfig } from "../config/config.js";

68

import { resolveConfigPath, resolveStateDir } from "../config/paths.js";

9+

import type { CliBackendConfig } from "../config/types.agent-defaults.js";

710

import type { GatewayAuthConfig } from "../config/types.gateway.js";

811

import type { SecurityAuditSuppression } from "../config/types.openclaw.js";

912

import { isInterpreterLikeAllowlistPattern } from "../infra/command-analysis/inline-eval.js";

10-

import { type ExecApprovalsFile, loadExecApprovals } from "../infra/exec-approvals.js";

13+

import {

14+

type ExecApprovalsFile,

15+

loadExecApprovals,

16+

maxAsk,

17+

minSecurity,

18+

resolveExecApprovalsFromFile,

19+

} from "../infra/exec-approvals.js";

1120

import {

1221

listInterpreterLikeSafeBins,

1322

resolveMergedSafeBinProfileFixtures,

@@ -42,6 +51,10 @@ type SecurityAuditExplicitGatewayAuth = {

4251

password?: string;

4352

};

4453

type SecurityAuditGatewayAuthOverride = Pick<GatewayAuthConfig, "mode" | "token" | "password">;

54+

type ClaudePermissionModeHit = {

55+

argSet: "args" | "resumeArgs";

56+

mode: string;

57+

};

45584659

export type {

4760

SecurityAuditFinding,

@@ -559,13 +572,127 @@ export function collectElevatedFindings(cfg: OpenClawConfig): SecurityAuditFindi

559572

return findings;

560573

}

561574575+

const CLAUDE_PERMISSION_MODE_FLAG = "--permission-mode";

576+

const CLAUDE_BYPASS_PERMISSION_MODE = "bypassPermissions";

577+578+

function extractClaudePermissionMode(args: readonly string[] | undefined): string | undefined {

579+

if (!Array.isArray(args)) {

580+

return undefined;

581+

}

582+

for (let i = args.length - 1; i >= 0; i -= 1) {

583+

const arg = args[i] ?? "";

584+

if (arg === CLAUDE_PERMISSION_MODE_FLAG) {

585+

const value = args[i + 1];

586+

if (typeof value === "string" && value.trim().length > 0 && !value.startsWith("-")) {

587+

return value.trim();

588+

}

589+

continue;

590+

}

591+

if (arg.startsWith(`${CLAUDE_PERMISSION_MODE_FLAG}=`)) {

592+

const value = arg.slice(`${CLAUDE_PERMISSION_MODE_FLAG}=`.length).trim();

593+

if (value.length > 0 && !value.startsWith("-")) {

594+

return value;

595+

}

596+

}

597+

}

598+

return undefined;

599+

}

600+601+

function collectRestrictiveClaudePermissionModeHits(

602+

backend: CliBackendConfig | undefined,

603+

): ClaudePermissionModeHit[] {

604+

if (!isManagedClaudeLiveBackendConfig(backend)) {

605+

return [];

606+

}

607+

const hits: ClaudePermissionModeHit[] = [];

608+

const argsMode = extractClaudePermissionMode(backend.args);

609+

if (argsMode && argsMode !== CLAUDE_BYPASS_PERMISSION_MODE) {

610+

hits.push({ argSet: "args", mode: argsMode });

611+

}

612+

const resumeArgsMode = extractClaudePermissionMode(backend.resumeArgs);

613+

if (resumeArgsMode && resumeArgsMode !== CLAUDE_BYPASS_PERMISSION_MODE) {

614+

hits.push({ argSet: "resumeArgs", mode: resumeArgsMode });

615+

}

616+

return hits;

617+

}

618+619+

function isManagedClaudeLiveBackendConfig(

620+

backend: CliBackendConfig | undefined,

621+

): backend is CliBackendConfig {

622+

if (!backend) {

623+

return false;

624+

}

625+

const output = backend.output ?? "jsonl";

626+

const input = backend.input ?? "stdin";

627+

const liveSession =

628+

backend.liveSession ?? (output === "jsonl" && input === "stdin" ? "claude-stdio" : undefined);

629+

return liveSession === "claude-stdio" && output === "jsonl" && input === "stdin";

630+

}

631+632+

function findClaudeCliBackendConfig(

633+

backends: Record<string, CliBackendConfig> | undefined,

634+

): CliBackendConfig | undefined {

635+

if (!backends) {

636+

return undefined;

637+

}

638+

const directKey = Object.keys(backends).find(

639+

(key) => normalizeOptionalLowercaseString(key) === "claude-cli",

640+

);

641+

if (directKey) {

642+

return backends[directKey];

643+

}

644+

for (const [key, backend] of Object.entries(backends)) {

645+

if (normalizeProviderId(key) === "claude-cli") {

646+

return backend;

647+

}

648+

}

649+

return undefined;

650+

}

651+652+

function collectYoloExecScopeIds(cfg: OpenClawConfig, approvals: ExecApprovalsFile): string[] {

653+

const agents = Array.isArray(cfg.agents?.list) ? cfg.agents.list : [];

654+

return [

655+

{ id: DEFAULT_AGENT_ID },

656+

...agents

657+

.filter(

658+

(entry): entry is NonNullable<(typeof agents)[number]> =>

659+

Boolean(entry) && typeof entry === "object" && typeof entry.id === "string",

660+

)

661+

.map((entry) => ({ id: entry.id })),

662+

]

663+

.filter((entry) => {

664+

const execDefaults = resolveExecDefaults({

665+

cfg,

666+

agentId: entry.id === DEFAULT_AGENT_ID ? undefined : entry.id,

667+

});

668+

const resolvedApprovals = resolveExecApprovalsFromFile({

669+

file: approvals,

670+

agentId: entry.id === DEFAULT_AGENT_ID ? undefined : entry.id,

671+

overrides: {

672+

security: execDefaults.security,

673+

ask: execDefaults.ask,

674+

},

675+

});

676+

return (

677+

minSecurity(execDefaults.security, resolvedApprovals.agent.security) === "full" &&

678+

maxAsk(execDefaults.ask, resolvedApprovals.agent.ask) === "off"

679+

);

680+

})

681+

.map((entry) => entry.id);

682+

}

683+562684

export function collectExecRuntimeFindings(cfg: OpenClawConfig): SecurityAuditFinding[] {

563685

const findings: SecurityAuditFinding[] = [];

564686

const globalExecHost = cfg.tools?.exec?.host;

565687

const globalStrictInlineEval = cfg.tools?.exec?.strictInlineEval === true;

566688

const defaultSandboxMode = resolveSandboxConfigForAgent(cfg).mode;

567689

const defaultHostIsExplicitSandbox = globalExecHost === "sandbox";

568690

const approvals = loadExecApprovals();

691+

const claudePermissionModeHits = collectRestrictiveClaudePermissionModeHits(

692+

findClaudeCliBackendConfig(cfg.agents?.defaults?.cliBackends),

693+

);

694+

const yoloExecScopeIds =

695+

claudePermissionModeHits.length > 0 ? collectYoloExecScopeIds(cfg, approvals) : [];

569696570697

if (defaultHostIsExplicitSandbox && defaultSandboxMode === "off") {

571698

findings.push({

@@ -646,6 +773,17 @@ export function collectExecRuntimeFindings(cfg: OpenClawConfig): SecurityAuditFi

646773

});

647774

}

648775776+

if (claudePermissionModeHits.length > 0 && yoloExecScopeIds.length > 0) {

777+

findings.push({

778+

checkId: "agents.claude_cli.permission_mode_overridden_by_yolo",

779+

severity: "warn",

780+

title: "Claude permission mode is ignored under YOLO exec",

781+

detail: `claude-cli sets ${claudePermissionModeHits.map((hit) => `${hit.argSet}=${hit.mode}`).join(", ")}, but OpenClaw exec is YOLO for: ${yoloExecScopeIds.join(", ")}. Managed Claude live sessions use --permission-mode bypassPermissions.`,

782+

remediation:

783+

"Restrict OpenClaw tools.exec.security/tools.exec.ask, or remove the Claude --permission-mode override.",

784+

});

785+

}

786+649787

if (openExecSurfacePaths.length > 0 && execEnabledScopes.length > 0) {

650788

findings.push({

651789

checkId: "security.exposure.open_channels_with_exec",