amp, goose: refuse to format resume commands for hostile session IDs - #57
Merged
Merged
Conversation
FormatResumeCommand concatenates the session ID, which arrives from a hook payload and is never validated, directly into the string the Entire CLI prints for the user to run. A hostile ID such as 'evil; rm -rf /' would execute arbitrary commands when the user runs the printed command. Add a safe-character allowlist that mirrors the validation already used by the kilo and qwen adapters and refuse to emit a resume command for any ID outside that set. Normal session IDs (amp thread IDs, goose YYYYMMDD_N names) are unaffected. Regression tests cover both valid identifiers and a range of injection payloads.
4 tasks
Entire-Checkpoint: c67224cd8221
There was a problem hiding this comment.
🟢 Approval recommended
The validation safely blocks shell and option injection while preserving documented valid behavior with focused test coverage.
Pull request overview
Adds shell-injection defenses to Amp and Goose resume-command formatting.
Changes:
- Validates session IDs against a safe ASCII allowlist and rejects option-like IDs.
- Preserves Amp’s empty-ID
--lastbehavior. - Adds unit coverage for valid IDs and hostile payloads.
File summaries
| File | Description |
|---|---|
agents/entire-agent-amp/internal/amp/agent.go |
Validates Amp resume session IDs. |
agents/entire-agent-amp/internal/amp/agent_test.go |
Tests valid, empty, and hostile Amp IDs. |
agents/entire-agent-goose/internal/goose/agent.go |
Validates Goose resume session IDs. |
agents/entire-agent-goose/internal/goose/agent_test.go |
Tests valid and rejected Goose IDs. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 0
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Member
|
@SparshM8 Thanks for the contribution! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Amp and Goose adapters build their resume command by concatenating the session ID from a hook payload directly into the command string returned to the Entire CLI. The CLI prints that string for the user to run verbatim, so a hostile session ID — for example
evil; rm -rf /,evil$(whoami), or an ID containing ANSI escape sequences — would execute arbitrary commands (or corrupt the terminal display) when the user runs the printed command. The session ID is attacker-controllable in at least the common case of crafting or tampering with hook payloads.This change adds input validation to
FormatResumeCommandin both adapters and refuses to emit a resume command for any session ID outside the character set that real Amp and Goose identifiers use. The validation mirrors the safe-rune allowlist already established by thekiloandqwenadapters, extending the same defensive contract to the two adapters that were still missing it.Why this matters
The native-agent path in the Entire CLI already validates session IDs before constructing its resume command (
isLaunchableResumeSessionID). External agents are the only remaining path where an unchecked, attacker-controlled identifier flows into a user-executable command string. The damage model is severe: a single crafted hook payload can turn the CLI's own resume prompt into an arbitrary-command execution surface, and because the printed command is assumed to be safe, the user has no reason to inspect it. Validating at the source — the adapter that formats the command — is the deepest and cheapest fix available.Changes
agents/entire-agent-amp/internal/amp/agent.goFormatResumeCommandnow validates the session ID against a safe-rune allowlist (a-zA-Z0-9-_.:) and returns an empty command when the ID is invalid. The empty-ID fallback (--last) is unchanged.agents/entire-agent-goose/internal/goose/agent.goFormatResumeCommandnow validates the session ID against the same allowlist (goose names areYYYYMMDD_N, which the allowlist fully covers) and returns an empty command for invalid IDs. The handler already serializes the empty string as an emptyCommandfield, so the CLI receives nothing to print instead of a hostile string.agents/entire-agent-amp/internal/amp/agent_test.go(new)TestFormatResumeCommandEmpty,TestFormatResumeCommandValidID, andTestFormatResumeCommandRefusesInjectionPayloadscovering thread IDs,YYYYMMDD_Nnames, and injection payloads such as command separators, command substitution, newlines, path traversal, and ANSI escapes.agents/entire-agent-goose/internal/goose/agent_test.go(new)TestFormatResumeCommandValidIDandTestFormatResumeCommandRefusesInvalidPayloadswith the same payload matrix, including the empty ID which Goose previously formatted unconditionally.Testing
TestFormatResumeCommandEmpty(amp)--lastfallback unchangedTestFormatResumeCommandValidID(amp)T-12345,20260816_42, dotted and mixed-case IDs passTestFormatResumeCommandRefusesInjectionPayloads(amp);,$(), backticks, newlines,..,~,|,&&, ANSI escapes, surrounding whitespace all refusedTestFormatResumeCommandValidID(goose)20260611_1,20260816_42and mixed-character IDs passTestFormatResumeCommandRefusesInvalidPayloads(goose)The new tests are deterministic unit tests: they need neither the Amp, Goose, nor Entire binaries.
Compatibility
The change is behavior-preserving for every deployment using real Amp thread IDs or Goose
YYYYMMDD_Nsession names, which is the only caseFormatResumeCommandcould have been called with meaningfully before. The only behavioral difference surfaces when a hostile or malformed ID reaches the formatter, which is precisely the case that must not be format-preserving. No protocol JSON surface, hook event format, transcript format, orkilo/kiro/omp/qwenbehavior changes.Checklist