Skip to content

feat(acp): add resumeSessionId to sessions_spawn for ACP session resume#41847

Merged
onutc merged 3 commits intoopenclaw:mainfrom
pejmanjohn:feat/acp-resume-session
Mar 10, 2026
Merged

feat(acp): add resumeSessionId to sessions_spawn for ACP session resume#41847
onutc merged 3 commits intoopenclaw:mainfrom
pejmanjohn:feat/acp-resume-session

Conversation

@pejmanjohn
Copy link
Contributor

@pejmanjohn pejmanjohn commented Mar 10, 2026

Summary

Add resumeSessionId parameter to sessions_spawn so agents can resume existing ACP sessions (e.g. a prior Codex conversation) instead of starting fresh. The agent replays conversation history via session/load.

Flow

sessions_spawn(resumeSessionId) → spawnAcpDirect → initializeSession →
ensureSession → acpx --resume-session → agent session/load

Changes

  • sessions-spawn-tool.ts — Add resumeSessionId param with description so agents discover and use it
  • acp-spawn.ts — Thread through SpawnAcpParams
  • manager.types.ts / manager.core.ts — Thread through AcpInitializeSessionInput
  • types.ts — Add to AcpRuntimeEnsureInput
  • extensions/acpx/src/runtime.ts — Pass as --resume-session flag to acpx CLI

All new fields are optional (backward-compatible).

Dependency

Requires acpx >= next release (openclaw/acpx#85 merged, pending npm publish). The --resume-session CLI flag was added there. Version bump commit will follow once published.

Testing

  • 26 unit tests pass (runtime + tool schema)
  • Verified e2e: Discord → sessions_spawn(resumeSessionId="...") → Codex resumed session and recalled stored secret
  • Tested locally with dev gateway
  • Lightly tested (e2e with dev bot, unit tests for all code paths)
  • I understand what the code does
CleanShot 2026-03-09 at 23 23 08@2x

🤖 AI-assisted (Codex for initial implementation, manually reviewed and refined)

Note: Happy to open a Discussion first if preferred for new ACP features — wanted to get the implementation up for visibility since the acpx side (PR #85) is already merged.

@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling extensions: acpx size: S labels Mar 10, 2026
@aisle-research-bot
Copy link

aisle-research-bot bot commented Mar 10, 2026

🔒 Aisle Security Analysis

We found 2 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium IDOR risk: sessions_spawn forwards user-controlled resumeSessionId to ACPX/Codex session resume without authorization/validation
2 🔵 Low Sensitive resumeSessionId exposed via child process command-line arguments (--resume-session)

1. 🟡 IDOR risk: sessions_spawn forwards user-controlled resumeSessionId to ACPX/Codex session resume without authorization/validation

Property Value
Severity Medium
CWE CWE-639
Location src/agents/tools/sessions-spawn-tool.ts:152-163

Description

The sessions_spawn tool now accepts an optional resumeSessionId and forwards it into the ACP runtime initialization flow, which ultimately runs ACPX with sessions new --resume-session <resumeSessionId>.

If sessions_spawn is available to untrusted/remote callers (e.g., chat users, group tenants, or any non-owner sender allowed to use the tool), this creates a cross-session data access risk:

  • resumeSessionId is taken directly from tool arguments and not validated (e.g., UUID-only) or scoped/authorized to the requesting user/session.
  • Downstream, ACPX/Codex is instructed to resume an existing session ID (commonly stored under a shared host directory such as ~/.codex/sessions/).
  • An attacker who can guess/obtain another session ID could resume it and cause its conversation history to be replayed into the spawned agent context, enabling data exfiltration (summaries, quotes, tool outputs, etc.).

Vulnerable flow (high-level):

  • input: resumeSessionId from sessions_spawn tool args (src/agents/tools/sessions-spawn-tool.ts)
  • propagation: spawnAcpDirectAcpSessionManager.initializeSessionAcpRuntime.ensureSession
  • sink: ACPX CLI invocation uses --resume-session with attacker-controlled value (extensions/acpx/src/runtime.ts builds ['sessions','new','--resume-session', resumeSessionId]).

Vulnerable code:

const result = await spawnAcpDirect(
  {
    task,
    label: label || undefined,
    agentId: requestedAgentId,
    resumeSessionId,
    cwd,
    mode: mode && ACP_SPAWN_MODES.includes(mode) ? mode : undefined,
    thread,
    sandbox,
    streamTo,
  },
  {
    agentSessionKey: opts?.agentSessionKey,
    ...
  },
);

Recommendation

Add authorization and validation before allowing resumeSessionId to be used.

At minimum:

  1. Validate format to reduce path/payload abuse and accidental misuse (UUID v4/v1 style).
  2. Restrict scope so callers can only resume sessions they own/created (or require explicit owner approval).
  3. Consider disabling this feature by default behind a config flag (opt-in).

Example (format validation + owner-only gate):

import { looksLikeSessionId } from "../../sessions/session-id.js";
import { ToolAuthorizationError, ToolInputError } from "./common.js";// ... inside execute
const resumeSessionId = readStringParam(params, "resumeSessionId");
if (resumeSessionId) {
  if (!looksLikeSessionId(resumeSessionId)) {
    throw new ToolInputError("resumeSessionId must be a UUID");
  }// If this tool can be invoked by non-owner senders, require owner or a config allowlist.
  if (!opts?.senderIsOwner) {
    throw new ToolAuthorizationError("resumeSessionId is restricted to owner senders.");
  }
}

Stronger approach: maintain a mapping of allowed resumeSessionIds per requester (or per agentSessionKey/accountId) and verify membership before passing it downstream.


2. 🔵 Sensitive resumeSessionId exposed via child process command-line arguments (--resume-session)

Property Value
Severity Low
CWE CWE-214
Location extensions/acpx/src/runtime.ts:206-213

Description

The ACPX runtime passes resumeSessionId as a raw command-line argument when resuming a session:

  • resumeSessionId is taken from AcpRuntimeEnsureInput and appended into the spawned acpx CLI argv (--resume-session <id>).
  • OS-level process inspection (e.g., /proc/<pid>/cmdline, ps, crash dumps, some process supervisors) can expose argv to other local users/processes.
  • This identifier is described as a Codex session UUID from ~/.codex/sessions/; leaking it may enable unintended correlation/access to prior conversation history in environments where session IDs are security-relevant.

Vulnerable code:

const resumeSessionId = asTrimmedString(input.resumeSessionId);
const ensureSubcommand = resumeSessionId
  ? ["sessions", "new", "--name", sessionName, "--resume-session", resumeSessionId]
  : ["sessions", "ensure", "--name", sessionName];

Recommendation

Avoid placing sensitive identifiers in process argv.

Options (best to worst):

  1. Pass the resume session id via stdin or a temp file (so it doesn't appear in ps output).
  2. Pass via environment variable (still sometimes exposed, but typically less visible than argv).
  3. If the acpx CLI requires argv, add a redaction layer anywhere commands are logged/telemetry-captured (and document that resumeSessionId is sensitive).

Example approach using an env var (requires acpx support; otherwise add a new CLI option that reads from env/stdin):

// Prefer: acpx reads resume id from env or stdin rather than argv
const env = { ...process.env, ACPX_RESUME_SESSION_ID: resumeSessionId };
spawn(resolved.command, resolved.args /* without resumeSessionId */, { cwd, env });

Analyzed PR: #41847 at commit d7950d9

Last updated on: 2026-03-10T09:56:22Z

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 10, 2026

Greptile Summary

This PR adds an optional resumeSessionId parameter to the sessions_spawn tool and threads it through the ACP stack (acp-spawn.tsmanager.core.tstypes.tsruntime.ts) so that the acpx CLI receives a --resume-session flag and replays an existing Codex conversation instead of starting a fresh one. All additions are backward-compatible (optional fields). The runtime-level logic in extensions/acpx/src/runtime.ts is clean, and both the runtime test and tool-layer test cover the happy path well.

One logic gap to address:

  • resumeSessionId silently ignored for the default subagent runtimeresumeSessionId is read in sessions-spawn-tool.ts but is never forwarded to spawnSubagentDirect. Because runtime defaults to "subagent" when not explicitly provided, an agent that passes resumeSessionId without also specifying runtime="acp" will silently receive a brand-new session rather than the resumed one. The codebase already has the right pattern for this: the streamTo parameter has an early-return guard. The same guard should be added for resumeSessionId, and the schema description should explicitly note the runtime=acp requirement.

Confidence Score: 2/5

  • Unsafe to merge without fixing the runtime guard for resumeSessionId — agents may silently create fresh sessions instead of resuming intended ones.
  • One verified logic bug in src/agents/tools/sessions-spawn-tool.ts: resumeSessionId parameter is silently dropped when runtime defaults to "subagent" (the default when not explicitly set). This mirrors a bug pattern that was already fixed for the streamTo parameter in the same function. The fix is straightforward (add an early-return guard and update the schema description), but without it, user input is silently ignored, leading to incorrect session behavior. All other type threads and ACP runtime logic are correct and well-tested.
  • src/agents/tools/sessions-spawn-tool.ts — add runtime guard for resumeSessionId and update schema description to mention runtime=acp requirement.

Comments Outside Diff (1)

  1. src/agents/tools/sessions-spawn-tool.ts, line 130-135 (link)

    resumeSessionId is read at line 100 but is never forwarded to spawnSubagentDirect. Because runtime defaults to "subagent" when not explicitly set, an agent that calls sessions_spawn({ task: "...", resumeSessionId: "..." }) without specifying runtime: "acp" will silently start a fresh session instead of resuming the intended one — with no error or warning.

    This is the same problem that was already solved for streamTo, which has an explicit runtime guard right above this block. The same pattern should be applied to resumeSessionId:

    Additionally, the resumeSessionId schema description (lines 28-33) should mention the runtime=acp requirement so agents discover this constraint before calling the tool.

Last reviewed commit: 1821ef4

@pejmanjohn
Copy link
Contributor Author

Addressed @greptile-apps feedback in 886a3d3:

  • Added early-return guard that errors when resumeSessionId is passed without runtime="acp" (mirrors the existing streamTo guard pattern)
  • Updated schema description to note the runtime=acp requirement
  • Added test for the guard (27/27 tests pass)

Good catch — without this, agents that omit runtime would silently get a fresh session instead of resuming.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 10, 2026

Perfect! The guard implementation looks clean:

  1. Early-return pattern matches the existing streamTo guard perfectly
  2. Clear error message tells users exactly what's wrong: resumeSessionId is only supported for runtime=acp; got runtime=${runtime}
  3. Schema updated to document the requirement upfront
  4. Test coverage verifies both the error path and that no spawn functions are called

This prevents the silent failure where agents would get a fresh session instead of resuming. Good catch and solid fix! ✅

@onutc onutc self-assigned this Mar 10, 2026
pejmanjohn and others added 3 commits March 10, 2026 10:23
Thread resumeSessionId through the ACP session spawn pipeline so agents
can resume existing sessions (e.g. a prior Codex conversation) instead
of starting fresh.

Flow: sessions_spawn tool → spawnAcpDirect → initializeSession →
ensureSession → acpx --resume-session flag → agent session/load

- Add resumeSessionId param to sessions-spawn-tool schema with
  description so agents can discover and use it
- Thread through SpawnAcpParams → AcpInitializeSessionInput →
  AcpRuntimeEnsureInput → acpx extension runtime
- Pass as --resume-session flag to acpx CLI
- Error hard (exit 4) on non-existent session, no silent fallback
- All new fields optional for backward compatibility

Depends on acpx >= 0.1.16 (openclaw/acpx#85, merged, pending release).

Tests: 26/26 pass (runtime + tool schema)
Verified e2e: Discord → sessions_spawn(resumeSessionId) → Codex
resumed session and recalled stored secret.

🤖 AI-assisted
Add early-return error when resumeSessionId is passed without
runtime="acp" (mirrors existing streamTo guard). Without this,
the parameter is silently ignored and the agent gets a fresh
session instead of resuming.

Also update schema description to note the runtime=acp requirement.

Addresses Greptile review feedback.
@onutc onutc force-pushed the feat/acp-resume-session branch from 886a3d3 to d7950d9 Compare March 10, 2026 09:34
@onutc onutc merged commit aca216b into openclaw:main Mar 10, 2026
27 checks passed
@onutc
Copy link
Contributor

onutc commented Mar 10, 2026

Landed after rebasing onto current main.

Thanks @pejmanjohn!

Get-windy pushed a commit to Get-windy/JieZi-ai-PS that referenced this pull request Mar 10, 2026
上游更新摘要(abb8f6310 → bda63c3,164 commits):

### 新功能
- ACP: 新增 resumeSessionId 支持 ACP session 恢复(openclaw#41847)
- CLI: 新增 openclaw backup create/verify 本地状态归档命令(openclaw#40163)
- Talk: 新增 talk.silenceTimeoutMs 配置项,可自定义静默超时(openclaw#39607)
- ACP Provenance: 新增 ACP 入站溯源元数据和回执注入(openclaw#40473)
- Brave 搜索: 新增 llm-context 模式,返回 AI 精炼摘要(openclaw#33383)
- browser.relayBindHost: Chrome relay 可绑定非 loopback 地址(WSL2 支持)(openclaw#39364)
- node-pending-work: 新增 node.pending.pull/ack RPC 接口
- Telegram: 新增 exec-approvals 处理器,支持 Telegram 内命令执行审批
- Mattermost: 新增 target-resolution,修复 markdown 保留和 DM media 上传
- MS Teams: 修复 Bot Framework General channel 对话 ID 兼容性(openclaw#41838)
- secrets/runtime-web-tools: 全新 web runtime secrets 工具模块
- cron: 新增 store-migration,isolated-agent 直送核心通道,delivery failure notify
- TUI: 自动检测浅色终端主题(COLORFGBG),支持 OPENCLAW_THEME 覆盖(openclaw#38636)

### 修复
- macOS: launchd 重启前重启已禁用服务,修复 openclaw update 卡死问题
- Telegram DM: 按 agent 去重入站 DM,防止同一条消息触发重复回复(openclaw#40519)
- Matrix DM: 修复 m.direct homeserver 检测,保留房间绑定优先级(openclaw#19736)
- 飞书: 清理插件发现缓存,修复 onboarding 安装后重复弹窗(openclaw#39642)
- config/runtime snapshots: 修复 config 写入后 secret 快照丢失问题(openclaw#37313)
- browser/CDP: 修复 ws:// CDP URL 反向代理和 wildcard 地址重写
- agents/failover: 识别 Bedrock tokens per day 限额为 rate limit

### 版本
- ACPX 0.1.16
- iOS/macOS 版本号更新
- Android: 精简后台权限

构建验证:待执行
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling extensions: acpx size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants