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

推荐订阅源

www.infosecurity-magazine.com
www.infosecurity-magazine.com
D
DataBreaches.Net
T
Tailwind CSS Blog
M
MIT News - Artificial intelligence
Stack Overflow Blog
Stack Overflow Blog
F
Full Disclosure
V2EX - 技术
V2EX - 技术
N
News and Events Feed by Topic
Help Net Security
Help Net Security
L
LangChain Blog
Y
Y Combinator Blog
宝玉的分享
宝玉的分享
Google Online Security Blog
Google Online Security Blog
P
Proofpoint News Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Blog of Author Tim Ferriss
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
B
Blog RSS Feed
N
Netflix TechBlog - Medium
N
News | PayPal Newsroom
TaoSecurity Blog
TaoSecurity Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
V
Vulnerabilities – Threatpost
B
Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
I
Intezer
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园_首页
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
AI
AI
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cyberwarzone
Cyberwarzone
P
Proofpoint News Feed
Google DeepMind News
Google DeepMind News
G
GRAHAM CLULEY
Vercel News
Vercel News
罗磊的独立博客
MyScale Blog
MyScale Blog
Last Week in AI
Last Week in AI
博客园 - 司徒正美
C
CERT Recently Published Vulnerability Notes
GbyAI
GbyAI
Scott Helme
Scott Helme
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Troy Hunt's Blog
A
About on SuperTechFans
P
Privacy International News Feed

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 test: trim doctor command hotspots · openclaw/openclaw@c66f16a test: isolate agent auth and spawn hotspots · openclaw/openclaw@9285935 test: stabilize MCP startup disposal race · openclaw/openclaw@dd9d2eb test: merge browser contract server suites · openclaw/openclaw@5817a76 test: narrow ollama provider discovery setup · openclaw/openclaw@a0d9598 build: declare qa-lab aimock runtime dependency · openclaw/openclaw@24431e5 test: speed up safe-bins exec harness · openclaw/openclaw@ee856ab test: preserve tool helpers in embedded runner mocks · openclaw/openclaw@acd86a0 refactor: move memory embeddings into provider plugins · openclaw/openclaw@77e6e4c test: reuse system-run temp fixtures · openclaw/openclaw@7e9ff0f test: trim hotspot wait overhead · openclaw/openclaw@12a59b0 Check: avoid duplicate boundary prep · openclaw/openclaw@baf11b8 test: reduce hotspot fixture overhead · openclaw/openclaw@3a59edd feat(ui): overhaul settings and slash command UX (#67819) thanks @Bun… · openclaw/openclaw@2cfb660 QA Matrix: exit cleanly on failure · openclaw/openclaw@42805d2 QA Matrix: isolate scenario coverage · openclaw/openclaw@7e659e1 Matrix: refresh crypto bootstrap state · openclaw/openclaw@94081d8 QA Lab: add provider registry · openclaw/openclaw@bb7e982 Matrix: add plugin changelog · openclaw/openclaw@4acab55 test: trim more hotspot overhead · openclaw/openclaw@f485311 test: trim remaining hotspot tests · openclaw/openclaw@6ba8626 test: narrow hotspot mocks · openclaw/openclaw@dbc8179 test: isolate gemini embedding request helpers · openclaw/openclaw@cd330f5 test: trim memory and mcp hotspots · openclaw/openclaw@fd48dfa test: slim provider registry mocks · openclaw/openclaw@2e08c77 test: harden Parallels update smoke · openclaw/openclaw@1a98090 feat: default Anthropic to Opus 4.7 · openclaw/openclaw@628b454 fix: harden node-host shell payload mutability checks · openclaw/openclaw@75c551e fix: land node-host approval binding for native binaries (#66731) (th… · openclaw/openclaw@29919bb CI: add daily schedule to CodeQL workflow (#67645) · openclaw/openclaw@69d25f5 fix(gateway): capture config hash after plugin auto-enable to prevent… · openclaw/openclaw@8c11210 fix: repair sanitized replay tool results before send (#67620) (thank… · openclaw/openclaw@c3c7a99 fix: restrict HTML timeout short-circuit to transient statuses · openclaw/openclaw@de129a6 fix: keep TUI watchdog bound to active run (#67401) (thanks @xantorres) · openclaw/openclaw@3525273 Gateway/skills: dedupe skills prefix-match + drop dead fallback on log · openclaw/openclaw@d7f489f Extensions/lmstudio: back off inference preload after consecutive fai… · openclaw/openclaw@b555214 TUI/streaming: add watchdog that resets the activity indicator after … · openclaw/openclaw@f44ab20 Agents/tool-loop: enable unknown-tool stream guard by default · openclaw/openclaw@36ed367 Gateway/skills: invalidate session skills snapshot on config write · openclaw/openclaw@b23d59a fix: classify HTML provider error pages correctly (#67642) (thanks @s… · openclaw/openclaw@e588e90 fix(skills): remove unused model-usage import (#67641) · openclaw/openclaw@55f05df docs(changelog): credit codex fix superseded PRs · openclaw/openclaw@e485f24 fix(openai-codex): normalize stale transport metadata in resolution a… · openclaw/openclaw@90801ba CI: pin Docker-related GitHub Actions (#67632) · openclaw/openclaw@f697b01 Android: modernize WebView and discovery API usage (#67627) · openclaw/openclaw@44a6e50 fix(deps): bump hono to 4.12.14 and @hono/node-server to 1.19.14 (GHS… · openclaw/openclaw@fbccc18 fix(deps): bump dompurify to 3.4.0 (#67614) · openclaw/openclaw@2c2dc00 CI: add explicit permissions to all workflow jobs (fixes code-scannin… · openclaw/openclaw@01b7516 fix: register bundled TTS providers and route overrides correctly (#6… · openclaw/openclaw@6ea3cdd fix: align host tilde paths with OS home (#62804) (thanks @stainlu) · openclaw/openclaw@ecfaf64 fix: flush creds queue before reconnect socket open (#67464) (thanks … · openclaw/openclaw@405c63f fix: strip standalone <function> tool call tags from visible text (#6… · openclaw/openclaw@78df859 fix(agents): preserve cli session metadata before transcript persist … · openclaw/openclaw@898fd04 docs(changelog): move cli transcript entry · openclaw/openclaw@c1817c6 fix(agents): normalize cli transcript api field · openclaw/openclaw@3a3fae0 docs(changelog): note cli transcript persistence · openclaw/openclaw@6c343f1 fix(agents): persist cli transcript turns · openclaw/openclaw@b8ef507 fix(msteams): harden security-sensitive flows (#65841) · openclaw/openclaw@c56b56e [Dashboard] Fix exec approval modal overflow for long command content… · openclaw/openclaw@053c5b0 Docs: remove QA changelog entry · openclaw/openclaw@7fd5771 QA: fix private runtime source loading (#67428) · openclaw/openclaw@d5933af docs(gateway): correct protocol.md schema path, hello-ok example, aut… · openclaw/openclaw@489404d CI: pin Node 22 runners to 22.18.0 · openclaw/openclaw@4ffa621 models.authStatus: normalize provider ids + tighten env-backed escape… · openclaw/openclaw@f2fdb9d Update CHANGELOG.md · openclaw/openclaw@7694a92 test(parallels): clean up npm update guard jobs · openclaw/openclaw@045ea7b Plugins: prefer scanDir override paths · openclaw/openclaw@b2974da fix(dreaming): default storage.mode to "separate" so phase blocks sto… · openclaw/openclaw@8c392f0 fix(memory-core): skip dreaming transcript ingestion via session stor… · openclaw/openclaw@a1b01f0 fix: dedupe replayed exec.finished node events (#67281) · openclaw/openclaw@5dcf526
fix(exec): bind node auto-review to prepared plans · openclaw/openclaw@b3dc7a4
steipete · 2026-05-30 · via Recent Commits to openclaw:main

@@ -6,6 +6,7 @@ import {

66

import { detectPolicyInlineEval } from "../infra/command-analysis/policy.js";

77

import {

88

type ExecApprovalsFile,

9+

type ExecAllowlistEntry,

910

type ExecAsk,

1011

type ExecSecurity,

1112

type SystemRunApprovalPlan,

@@ -19,7 +20,11 @@ import {

1920

parsePreparedSystemRunPayload,

2021

type PreparedRunExecPolicy,

2122

} from "../infra/system-run-approval-context.js";

22-

import { formatExecCommand, resolveSystemRunCommandRequest } from "../infra/system-run-command.js";

23+

import {

24+

extractShellCommandFromArgv,

25+

formatExecCommand,

26+

resolveSystemRunCommandRequest,

27+

} from "../infra/system-run-command.js";

2328

import { normalizeNullableString } from "../shared/string-coerce.js";

2429

import { resolveSafeTimeoutDelayMs } from "../utils/timer-delay.js";

2530

import type { ExecuteNodeHostCommandParams } from "./bash-tools.exec-host-node.types.js";

@@ -85,6 +90,47 @@ function resolveNodeRunTimeoutMs(runTimeoutSec: number): number {

8590

: 0;

8691

}

879293+

type NodePolicyCommandEval = {

94+

command: string;

95+

cwd: string | undefined;

96+

allowlistEval: ReturnType<typeof evaluateShellAllowlist>;

97+

};

98+99+

function hasExactCommandDurableApproval(params: {

100+

allowlist: readonly ExecAllowlistEntry[];

101+

commandText: string;

102+

}): boolean {

103+

const normalizedCommand = params.commandText.trim();

104+

if (!normalizedCommand) {

105+

return false;

106+

}

107+

const commandPattern = `=command:${crypto

108+

.createHash("sha256")

109+

.update(normalizedCommand)

110+

.digest("hex")

111+

.slice(0, 16)}`;

112+

return params.allowlist.some(

113+

(entry) =>

114+

entry.source === "allow-always" &&

115+

(entry.pattern === commandPattern ||

116+

(typeof entry.commandText === "string" && entry.commandText.trim() === normalizedCommand)),

117+

);

118+

}

119+120+

function extractPreparedNodeShellPayload(argv: readonly string[]): string | null {

121+

const extracted = extractShellCommandFromArgv([...argv]);

122+

if (extracted) {

123+

return extracted;

124+

}

125+

const executable = argv[0]?.split(/[\\/]/).pop()?.toLowerCase();

126+

const flag = argv[1]?.trim();

127+

const payload = argv[2]?.trim();

128+

if (argv.length === 3 && executable === "sh" && flag === "-lc" && payload) {

129+

return payload;

130+

}

131+

return null;

132+

}

133+88134

export function shouldSkipNodeApprovalPrepare(params: {

89135

hostSecurity: ExecSecurity;

90136

hostAsk: ExecAsk;

@@ -332,22 +378,76 @@ export async function analyzeNodeApprovalRequirement(params: {

332378

hostSecurity: ExecSecurity;

333379

hostAsk: ExecAsk;

334380

}): Promise<NodeApprovalAnalysis> {

381+

const approvalCommand = params.prepared.rawCommand;

382+

const approvalCwd = params.prepared.cwd ?? params.request.workdir;

335383

const baseAllowlistEval = evaluateShellAllowlist({

336-

command: params.request.command,

384+

command: approvalCommand,

337385

allowlist: [],

338386

safeBins: new Set(),

339-

cwd: params.request.workdir,

387+

cwd: approvalCwd,

340388

env: params.request.env,

341389

platform: params.target.platform,

342390

trustedSafeBinDirs: params.request.trustedSafeBinDirs,

343391

});

392+

const bindingCommandEvals: NodePolicyCommandEval[] = [

393+

{

394+

command: approvalCommand,

395+

cwd: approvalCwd,

396+

allowlistEval: baseAllowlistEval,

397+

},

398+

];

399+

const addCommandEval = (

400+

entries: NodePolicyCommandEval[],

401+

command: string | null | undefined,

402+

cwd: string | undefined,

403+

) => {

404+

const normalizedCommand = command?.trim();

405+

if (!normalizedCommand) {

406+

return;

407+

}

408+

if (entries.some((entry) => entry.command.trim() === normalizedCommand && entry.cwd === cwd)) {

409+

return;

410+

}

411+

entries.push({

412+

command: normalizedCommand,

413+

cwd,

414+

allowlistEval: evaluateShellAllowlist({

415+

command: normalizedCommand,

416+

allowlist: [],

417+

safeBins: new Set(),

418+

cwd,

419+

env: params.request.env,

420+

platform: params.target.platform,

421+

trustedSafeBinDirs: params.request.trustedSafeBinDirs,

422+

}),

423+

});

424+

};

425+

const preparedCommand = resolveSystemRunCommandRequest({

426+

command: params.prepared.argv,

427+

rawCommand: params.prepared.rawCommand,

428+

});

429+

const preparedShellPayload =

430+

extractPreparedNodeShellPayload(params.prepared.argv) ??

431+

(preparedCommand.ok ? preparedCommand.shellPayload : null);

432+

addCommandEval(bindingCommandEvals, preparedShellPayload, approvalCwd);

433+

const autoReviewBindingCommand = preparedShellPayload?.trim() || approvalCommand;

434+

const autoReviewBindingEval =

435+

bindingCommandEvals.find(

436+

(entry) =>

437+

entry.command.trim() === autoReviewBindingCommand.trim() && entry.cwd === approvalCwd,

438+

)?.allowlistEval ?? baseAllowlistEval;

439+

const policyCommandEvals = [...bindingCommandEvals];

440+

addCommandEval(policyCommandEvals, params.prepared.plan.commandPreview, approvalCwd);

441+

addCommandEval(policyCommandEvals, params.request.command, params.request.workdir);

344442

let analysisOk = baseAllowlistEval.analysisOk;

345443

let allowlistSatisfied = false;

346444

let durableApprovalSatisfied = false;

347445

let nodeApprovalsFileKnown = false;

348446

const inlineEvalHit =

349447

params.request.strictInlineEval === true

350-

? detectPolicyInlineEval(baseAllowlistEval.segments)

448+

? (policyCommandEvals

449+

.map((entry) => detectPolicyInlineEval(entry.allowlistEval.segments))

450+

.find((hit) => hit !== null) ?? null)

351451

: null;

352452

if (inlineEvalHit) {

353453

params.request.warnings.push(

@@ -356,13 +456,21 @@ export async function analyzeNodeApprovalRequirement(params: {

356456

)}.`,

357457

);

358458

}

459+

const suppressionCommandEvals =

460+

preparedShellPayload && preparedShellPayload.trim().length > 0

461+

? policyCommandEvals.filter(

462+

(entry) => entry.command.trim() !== approvalCommand.trim() || entry.cwd !== approvalCwd,

463+

)

464+

: policyCommandEvals;

359465

const requiresSecurityAuditSuppressionApproval =

360-

commandRequiresSecurityAuditSuppressionApproval({

361-

command: params.request.command,

362-

cwd: params.request.workdir,

363-

env: params.request.env,

364-

segments: baseAllowlistEval.segments,

365-

}) && !(params.hostSecurity === "full" && params.hostAsk === "off");

466+

suppressionCommandEvals.some((entry) =>

467+

commandRequiresSecurityAuditSuppressionApproval({

468+

command: entry.command,

469+

cwd: entry.cwd,

470+

env: params.request.env,

471+

segments: entry.allowlistEval.segments,

472+

}),

473+

) && !(params.hostSecurity === "full" && params.hostAsk === "off");

366474

if (

367475

(params.hostAsk === "always" ||

368476

params.hostSecurity === "allowlist" ||

@@ -383,27 +491,48 @@ export async function analyzeNodeApprovalRequirement(params: {

383491

nodeApprovalsFileKnown = true;

384492

const resolved = resolveExecApprovalsFromFile({

385493

file: approvalsFile as ExecApprovalsFile,

386-

agentId: params.request.agentId,

494+

agentId: params.prepared.agentId,

387495

overrides: { security: "full" },

388496

});

389497

// Allowlist-only precheck; safe bins are node-local and may diverge.

390-

const allowlistEval = evaluateShellAllowlist({

391-

command: params.request.command,

392-

allowlist: resolved.allowlist,

393-

safeBins: new Set(),

394-

cwd: params.request.workdir,

395-

env: params.request.env,

396-

platform: params.target.platform,

397-

trustedSafeBinDirs: params.request.trustedSafeBinDirs,

398-

});

399-

durableApprovalSatisfied = hasDurableExecApproval({

400-

analysisOk: allowlistEval.analysisOk,

401-

segmentAllowlistEntries: allowlistEval.segmentAllowlistEntries,

402-

allowlist: resolved.allowlist,

403-

commandText: params.prepared.rawCommand,

498+

// POSIX node transport wraps commands, so mirror node policy by

499+

// accepting either the prepared wrapper or its semantic inner command.

500+

const allowlistEvals = bindingCommandEvals.map((entry) => {

501+

const allowlistEval = evaluateShellAllowlist({

502+

command: entry.command,

503+

allowlist: resolved.allowlist,

504+

safeBins: new Set(),

505+

cwd: entry.cwd,

506+

env: params.request.env,

507+

platform: params.target.platform,

508+

trustedSafeBinDirs: params.request.trustedSafeBinDirs,

509+

});

510+

return {

511+

command: entry.command,

512+

allowlistEligible:

513+

!preparedShellPayload || entry.command.trim() === preparedShellPayload.trim(),

514+

exactDurableApprovalSatisfied: hasExactCommandDurableApproval({

515+

allowlist: resolved.allowlist,

516+

commandText: entry.command,

517+

}),

518+

allowlistEval,

519+

durableApprovalSatisfied: hasDurableExecApproval({

520+

analysisOk: allowlistEval.analysisOk,

521+

segmentAllowlistEntries: allowlistEval.segmentAllowlistEntries,

522+

allowlist: resolved.allowlist,

523+

commandText: entry.command,

524+

}),

525+

};

404526

});

405-

allowlistSatisfied = allowlistEval.allowlistSatisfied;

406-

analysisOk = allowlistEval.analysisOk;

527+

durableApprovalSatisfied = allowlistEvals.some(

528+

(entry) =>

529+

entry.durableApprovalSatisfied &&

530+

(entry.allowlistEligible || entry.exactDurableApprovalSatisfied),

531+

);

532+

allowlistSatisfied = allowlistEvals.some(

533+

(entry) => entry.allowlistEligible && entry.allowlistEval.allowlistSatisfied,

534+

);

535+

analysisOk = allowlistEvals.some((entry) => entry.allowlistEval.analysisOk);

407536

}

408537

} catch {

409538

// Fall back to requiring approval if node approvals cannot be fetched.

@@ -419,10 +548,10 @@ export async function analyzeNodeApprovalRequirement(params: {

419548

inlineEvalHit,

420549

requiresSecurityAuditSuppressionApproval,

421550

autoReviewArgv:

422-

baseAllowlistEval.segments.length === 1 &&

423-

(baseAllowlistEval.segments[0]?.raw === undefined ||

424-

baseAllowlistEval.segments[0].raw.trim() === params.request.command.trim())

425-

? baseAllowlistEval.segments[0].argv

551+

autoReviewBindingEval.segments.length === 1 &&

552+

(autoReviewBindingEval.segments[0]?.raw === undefined ||

553+

autoReviewBindingEval.segments[0].raw.trim() === autoReviewBindingCommand.trim())

554+

? autoReviewBindingEval.segments[0].argv

426555

: undefined,

427556

};

428557

}