Skip to content

fix(sessions_spawn): tolerate ACP-only fields for subagent runtime#72614

Merged
vincentkoc merged 7 commits into
mainfrom
clownfish/ghcrawl-156598-autonomous-smoke
Apr 27, 2026
Merged

fix(sessions_spawn): tolerate ACP-only fields for subagent runtime#72614
vincentkoc merged 7 commits into
mainfrom
clownfish/ghcrawl-156598-autonomous-smoke

Conversation

@vincentkoc

Copy link
Copy Markdown
Member

Summary

  • Treat streamTo and resumeSessionId as ACP-only values consumed only when runtime="acp".
  • For runtime="subagent", ignore those ACP-only fields before dispatch so schema-following providers cannot fail otherwise valid subagent spawns.
  • Preserve ACP pass-through semantics and add focused regression coverage.

Credit

This carries forward the focused implementation work from #68397, #65282, #58686, #56342, and #40102. Contributor credit is preserved in this PR and the changelog entry.

Validation

  • pnpm -s vitest run src/agents/tools/sessions-spawn-tool.test.ts
  • pnpm check:changed

Notes

This PR intentionally does not change ACP resumeSessionId authorization or session ownership semantics. Security-sensitive refs #63121 and #72331 remain routed to central OpenClaw security handling.

ProjectClownfish replacement details:

@greptile-apps

greptile-apps Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR changes sessions_spawn to silently ignore streamTo and resumeSessionId when runtime=\"subagent\" (or when runtime is omitted and defaults to subagent), rather than returning an error. ACP passthrough semantics are fully preserved, and the streamTo schema description was updated to reflect the ACP-only nature of the field. The test suite is updated accordingly with focused regression coverage.

Confidence Score: 4/5

Safe to merge; the logic change is intentional, well-tested, and limited to dropping ACP-only fields before a subagent dispatch.

Only P2 findings present. The implementation correctly strips the ACP-only fields in the subagent path and the tests verify both the stripping and the ACP passthrough. The one gap is a stale schema description for resumeSessionId that was not updated in parallel with streamTo.

src/agents/tools/sessions-spawn-tool.ts — resumeSessionId description update

Comments Outside Diff (1)

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

    P2 Stale resumeSessionId description still says "Requires runtime='acp'"

    The description for resumeSessionId still says Requires runtime="acp" but enforcement was removed in this PR — the field is now silently ignored for subagent runtime. streamTo was updated to say "ACP-only stream target" but resumeSessionId was not updated to match. An LLM following the schema description will infer an error will occur if it passes this field without runtime="acp", which is now incorrect and may cause unnecessary call-site gymnastics.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/agents/tools/sessions-spawn-tool.ts
    Line: 154-158
    
    Comment:
    **Stale `resumeSessionId` description still says "Requires runtime='acp'"**
    
    The description for `resumeSessionId` still says `Requires runtime="acp"` but enforcement was removed in this PR — the field is now silently ignored for subagent runtime. `streamTo` was updated to say `"ACP-only stream target"` but `resumeSessionId` was not updated to match. An LLM following the schema description will infer an error will occur if it passes this field without `runtime="acp"`, which is now incorrect and may cause unnecessary call-site gymnastics.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/tools/sessions-spawn-tool.ts
Line: 154-158

Comment:
**Stale `resumeSessionId` description still says "Requires runtime='acp'"**

The description for `resumeSessionId` still says `Requires runtime="acp"` but enforcement was removed in this PR — the field is now silently ignored for subagent runtime. `streamTo` was updated to say `"ACP-only stream target"` but `resumeSessionId` was not updated to match. An LLM following the schema description will infer an error will occur if it passes this field without `runtime="acp"`, which is now incorrect and may cause unnecessary call-site gymnastics.

```suggestion
          resumeSessionId: Type.Optional(
            Type.String({
              description:
                'ACP-only: resume an existing agent session by its ID (e.g. a Codex session UUID from ~/.codex/sessions/). Only meaningful for runtime="acp"; silently ignored for runtime="subagent". The agent replays conversation history via session/load instead of starting fresh.',
            }),
          ),
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(sessions_spawn): tolerate ACP-only f..." | Re-trigger Greptile

@vincentkoc
vincentkoc force-pushed the clownfish/ghcrawl-156598-autonomous-smoke branch from 0443906 to 69446c6 Compare April 27, 2026 06:16
@vincentkoc

Copy link
Copy Markdown
Member Author

ProjectClownfish pushed a narrow repair to this branch so the original contributor path can stay canonical.

Source PR: #72614
Validation: pnpm -s vitest run src/agents/tools/sessions-spawn-tool.test.ts; pnpm check:changed
Contributor credit is preserved in the branch history and PR context.

@openclaw-barnacle openclaw-barnacle Bot added the docs Improvements or additions to documentation label Apr 27, 2026
@vincentkoc

Copy link
Copy Markdown
Member Author

ProjectClownfish pushed a narrow repair to this branch so the original contributor path can stay canonical.

Source PR: #72614
Validation: pnpm -s vitest run src/agents/tools/sessions-spawn-tool.test.ts; pnpm check:changed
Contributor credit is preserved in the branch history and PR context.

@vincentkoc
vincentkoc force-pushed the clownfish/ghcrawl-156598-autonomous-smoke branch from 7056b56 to 2afa9ae Compare April 27, 2026 10:13
@vincentkoc
vincentkoc force-pushed the clownfish/ghcrawl-156598-autonomous-smoke branch 3 times, most recently from 25c1312 to 8062f56 Compare April 27, 2026 11:07
@aisle-research-bot

aisle-research-bot Bot commented Apr 27, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

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

# Severity Title
1 🟡 Medium sessions_spawn ACP resumeSessionId not redacted when tool arguments are JSON strings
1. 🟡 sessions_spawn ACP resumeSessionId not redacted when tool arguments are JSON strings
Property Value
Severity Medium
CWE CWE-532
Location src/agents/session-transcript-repair.ts:83-103

Description

sanitizeToolCallInputs() only redacts sessions_spawn fields (resumeSessionId, streamTo, and inline attachments[].content) when block.arguments/block.input are objects.

However, some tool-call block formats (notably OpenAI-style functionCall) commonly represent arguments as a JSON string. In that case, redactSessionsSpawnAcpArgs() / redactSessionsSpawnAttachmentsArgs() early-return without modification, so the sensitive ACP routing value can be persisted into transcripts/logs.

Impact:

  • resumeSessionId (an ACP session identifier) may be written to disk in session transcripts despite the new redaction logic.
  • This can enable cross-session correlation or unintended disclosure to operators/users who can read stored transcripts.

Vulnerable code:

function redactSessionsSpawnAcpArgs(value: unknown): unknown {
  if (!value || typeof value !== "object") {
    return value; // JSON-string arguments are not redacted
  }
  ...
}

Recommendation

Handle stringified tool arguments/inputs by attempting to parse JSON when the value is a string, redact in the parsed object, then re-serialize.

Example fix:

function redactSessionsSpawnArgs(value: unknown): unknown {// First handle object payloads
  const direct = redactSessionsSpawnAcpArgs(redactSessionsSpawnAttachmentsArgs(value));
  if (direct !== value) return direct;// Then handle JSON-string payloads (OpenAI functionCall style)
  if (typeof value === "string") {
    try {
      const parsed = JSON.parse(value) as unknown;
      const redacted = redactSessionsSpawnAcpArgs(redactSessionsSpawnAttachmentsArgs(parsed));
      return redacted === parsed ? value : JSON.stringify(redacted);
    } catch {
      return value;
    }
  }

  return value;
}

Also add tests covering type: "functionCall" blocks where arguments is a JSON string containing resumeSessionId/streamTo.


Analyzed PR: #72614 at commit a4b865b

Last updated on: 2026-04-27T16:36:13Z

@vincentkoc

Copy link
Copy Markdown
Member Author

ProjectClownfish follow-up: the Greptile note is addressed in the current head. resumeSessionId now describes the field as ACP-only and explicitly says it is ignored for runtime="subagent".

@vincentkoc

Copy link
Copy Markdown
Member Author

ProjectClownfish follow-up: addressed the Aisle transcript finding in the current head. sessions_spawn now redacts ACP-only resumeSessionId and streamTo fields in both persisted arguments and input payloads, with regression coverage for both shapes.

@vincentkoc
vincentkoc force-pushed the clownfish/ghcrawl-156598-autonomous-smoke branch from 2b1d89e to fa0fd0e Compare April 27, 2026 11:38
@vincentkoc

Copy link
Copy Markdown
Member Author

ProjectClownfish follow-up: addressed the latest Aisle edge case too. ACP-only sessions_spawn routing keys are now redacted by key presence, not by string type, so object/array/number payloads cannot persist through transcript repair. Remote Blacksmith validation: pnpm test:serial src/agents/session-transcript-repair.attachments.test.ts src/agents/session-transcript-repair.test.ts passed (38 tests).

@vincentkoc

Copy link
Copy Markdown
Member Author

ProjectClownfish follow-up: addressed the Aisle IDOR finding in the current head. runtime="acp" resumeSessionId now passes only when it matches an ACP identity already recorded in OpenClaw session state and owned by the requester session; otherwise it returns resume_forbidden before sessions.patch or ACP runtime initialization. Remote Blacksmith validation passed: pnpm test:serial src/agents/acp-spawn.test.ts src/agents/tools/sessions-spawn-tool.test.ts src/agents/session-transcript-repair.attachments.test.ts src/agents/session-transcript-repair.test.ts (115 tests).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling clawsweeper Tracked by ClawSweeper automation docs Improvements or additions to documentation maintainer Maintainer-authored PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant