Back to skill

Security audit

Gstack Orchestrate

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it needs review because it can make substantial repository changes and stores shell state in a way that can run unintended commands.

Review before installing. Use only on trusted repositories and branches, disable telemetry if you do not want remote reporting, and fix the env.sh/tel-state serialization to use shell-safe quoting or JSON before relying on it for untrusted repos.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:230
Finding

Arbitrary Command Execution Through Unsafe Generated Shell Environment File

Content
View full analysis
"$_STATE_DIR/env.sh" <" ``` ### Technical Analysis The Skill serializes multiple dynamically derived values into an executable shell script without shell escaping. These values include the repository path, Git branch name, state paths, and potentially a user-provided test command. Placing a value between literal double quotes in generated shell source is not safe unless shell metacharacters are escaped. A value containing a double quote can terminate the assignment, while characters such as semicolons, command substitutions, variable expansions, and comment markers can introduce executable shell syntax. Although interpolation into the heredoc does not immediately reinterpret shell syntax contained in variable values, the malicious syntax is written verbatim into `env.sh`. The later `source` operation parses that file as shell code, activating the injected commands. Git reference names permit several shell metacharacters, including double quotes, dollar signs, parentheses, semicolons, and comment markers in otherwise valid names. Consequently, a malicious repository can use a crafted branch name to inje ...[truncated 2279 chars]
Remediation
View remediation
"$_STATE_DIR/env.json" ``` Read individual fields as data rather than sourcing the file: ```bash _REPO_ROOT=$(jq -r '.repo_root' "$_STATE_DIR/env.json") _BRANCH=$(jq -r '.branch' "$_STATE_DIR/env.json") ``` If an executable environment file is unavoidable, serialize every value with shell-safe quoting: ```bash { printf 'export _REPO_ROOT=%q\n' "$_REPO_ROOT" printf 'export _BASE=%q\n' "$_BASE" printf 'export _BASE_SHA=%q\n' "$_BASE_SHA" printf 'export _BRANCH=%q\n' "$_BRANCH" printf 'export _BRANCH_SAFE=%q\n' "$_BRANCH_SAFE" printf 'export _STATE_DIR=%q\n' "$_STATE_DIR" printf 'export SLUG=%q\n' "$SLUG" printf 'export STACK=%q\n' "$STACK" printf 'export TEST_CMD=%q\n' "$TEST_CMD" printf 'export LINT_CMD=%q\n' "$LINT_CMD" printf 'export _COMMIT_FORMAT=%q\n' "$_COMMIT_FORMAT" printf 'export _TEL=%q\n' "$_TEL" printf 'export _TEL_START=%q\n' "$_TEL_START" printf 'export _SESSION_ID=%q\n' "$_SESSION_ID" printf 'export _OUTCOME=%q\n' "$_OUTCOME" } > "$_STATE_DIR/env.sh" chmod 600 "$_STATE_DIR/env.sh" ``` Additional hardening should include: 1. Validate Git branch names and reject unexpected shell metacharacters before generating state. 2. Keep user-provided test and lint commands as argument arrays or explicitly approved commands rather than executable strings. 3. Avoid executing `$TEST_CMD` and `$LINT_CMD` through implicit shell evaluation where possible. 4. Create state files with restrictive permissions and ensure the state directory is owned by the current u ...[truncated 284 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (30)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
65% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · README.md (reported line 67)May include surrounding context.

md
## What's NOT working yet

- **Worktree branches accumulate.** The Agent tool's `isolation: "worktree"` mode leaves auto-managed branches behind. The skill prunes worktree records but does NOT auto-delete branches (deleting them is unsafe — we can't reliably tell harness branches apart from user branches). Run `git branch --list` and clean manually if they pile up.
- **Resume divergence is detected, not auto-recovered.** If you `git reset --hard` between runs, the skill correctly refuses to resume but won't try to rebuild missing commits.
- **No `/ship` integration test.** Phase 4 calls `Skill({skill: "ship"})` but the handoff has only been validated as a code path, not a real shipping flow.

---

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
86% confidence
Finding

The skill reads from the agent configuration area under ~/.claude/skills/gstack/VERSION, demonstrating access to agent-managed configuration directories outside the repository. In isolation this read is low sensitivity, but granting a skill broad Bash access to agent config paths normalizes a dangerous trust boundary crossing that could be extended to secrets or other internal state.

Content

Scanner excerpt · SKILL.md (reported line 73)May include surrounding context.

md
mkdir -p ~/.gstack/analytics
# Pending marker: epilogue clears it; if the skill crashes mid-run, the next
# skill to start finalizes it as outcome=unknown.
echo '{"skill":"gstack-orchestrate","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","session_id":"'"$_SESSION_ID"'","gstack_version":"'$(cat ~/.claude/skills/gstack/VERSION 2>/dev/null | tr -d '[:space:]' || echo unknown)'"}' \
  > ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true

# Local analytics start row (gated on telemetry tier)

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · SKILL.md (reported line 122)May include surrounding context.

bash
# REPLACE <TEL_STATE_PATH> with the absolute path the preamble printed.
source <TEL_STATE_PATH>
sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="error"/' <TEL_STATE_PATH> && rm -f <TEL_STATE_PATH>.bak
# Then run the Phase 4.4.5 telemetry epilogue (which sources env.sh OR the
# tel-state file via literal substitution), and stop.

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · SKILL.md (reported line 301)May include surrounding context.

bash
# REPLACE <TEL_STATE_PATH> with the absolute path the preamble printed.
source <TEL_STATE_PATH>
sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="error"/' <TEL_STATE_PATH> && rm -f <TEL_STATE_PATH>.bak
# Then run the Phase 4.4.5 telemetry epilogue (which sources env.sh OR the
# tel-state file via literal substitution), and stop.

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · SKILL.md (reported line 315)May include surrounding context.

bash
# REPLACE <TEL_STATE_PATH> with the absolute path the preamble printed.
source <TEL_STATE_PATH>
sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="error"/' <TEL_STATE_PATH> && rm -f <TEL_STATE_PATH>.bak
# Then run the Phase 4.4.5 telemetry epilogue (which sources env.sh OR the
# tel-state file via literal substitution), and stop.

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · SKILL.md (reported line 423)May include surrounding context.

bash
# REPLACE <TEL_STATE_PATH> with the absolute path the preamble printed.
source <TEL_STATE_PATH>
sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="error"/' <TEL_STATE_PATH> && rm -f <TEL_STATE_PATH>.bak
# Then run the Phase 4.4.5 telemetry epilogue (which sources env.sh OR the
# tel-state file via literal substitution), and stop.

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · SKILL.md (reported line 675)May include surrounding context.

bash
# REPLACE <TEL_STATE_PATH> with the absolute path the preamble printed.
source <TEL_STATE_PATH>
sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="error"/' <TEL_STATE_PATH> && rm -f <TEL_STATE_PATH>.bak
# Then run the Phase 4.4.5 telemetry epilogue (which sources env.sh OR the
# tel-state file via literal substitution), and stop.

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · SKILL.md (reported line 717)May include surrounding context.

bash
# REPLACE <TEL_STATE_PATH> with the absolute path the preamble printed.
source <TEL_STATE_PATH>
sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="error"/' <TEL_STATE_PATH> && rm -f <TEL_STATE_PATH>.bak
# Then run the Phase 4.4.5 telemetry epilogue (which sources env.sh OR the
# tel-state file via literal substitution), and stop.

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · SKILL.md (reported line 781)May include surrounding context.

bash
# REPLACE <TEL_STATE_PATH> with the absolute path the preamble printed.
source <TEL_STATE_PATH>
sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="error"/' <TEL_STATE_PATH> && rm -f <TEL_STATE_PATH>.bak
# Then run the Phase 4.4.5 telemetry epilogue (which sources env.sh OR the
# tel-state file via literal substitution), and stop.

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · SKILL.md (reported line 852)May include surrounding context.

bash
# REPLACE <TEL_STATE_PATH> with the absolute path the preamble printed.
source <TEL_STATE_PATH>
sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="error"/' <TEL_STATE_PATH> && rm -f <TEL_STATE_PATH>.bak
# Then run the Phase 4.4.5 telemetry epilogue (which sources env.sh OR the
# tel-state file via literal substitution), and stop.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
89% confidence
Finding

The skill instructs deletion of files via rm using variables derived from runtime state. Although the path is intended to be controlled, any weakness in SLUG/branch sanitization, state-dir computation, or environment-file sourcing could redirect deletion to unintended files, and wildcard expansion on results/*.json amplifies the blast radius.

Content

Scanner excerpt · SKILL.md (reported line 300)May include surrounding context.

md
Then ask via `AskUserQuestion`:

- A) Resume from wave N+1 (only safe if `RESUME_OK` or `RESUME_OK_AHEAD`)
- B) Start fresh (`rm "$_STATE_DIR/state.jsonl" "$_STATE_DIR/TASKS.md" "$_STATE_DIR/results"/*.json` and re-shred)
- C) Abort. Set `_OUTCOME=abort` in env.sh (`sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="abort"/' "$_STATE_DIR/env.sh" && rm -f "$_STATE_DIR/env.sh.bak"`), run the Phase 4.4.5 epilogue, leave state intact for manual fix.

If `RESUME_DIVERGED` is detected, do NOT offer A. Force the user to pick B or C.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Removing backup files derived from $_STATE_DIR/env.sh.bak is a lower-severity case of the same path-manipulation risk. If the state directory is ever corrupted or attacker-influenced, cleanup commands may delete unintended files outside the intended workspace.

Content

Scanner excerpt · SKILL.md (reported line 301)May include surrounding context.

md
- A) Resume from wave N+1 (only safe if `RESUME_OK` or `RESUME_OK_AHEAD`)
- B) Start fresh (`rm "$_STATE_DIR/state.jsonl" "$_STATE_DIR/TASKS.md" "$_STATE_DIR/results"/*.json` and re-shred)
- C) Abort. Set `_OUTCOME=abort` in env.sh (`sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="abort"/' "$_STATE_DIR/env.sh" && rm -f "$_STATE_DIR/env.sh.bak"`), run the Phase 4.4.5 epilogue, leave state intact for manual fix.

If `RESUME_DIVERGED` is detected, do NOT offer A. Force the user to pick B or C.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

This repeats the same deletion pattern in a universal abort/error path, making the risky behavior broadly reachable. Reuse across multiple stop points increases exposure because the command may run under exceptional conditions when state is already inconsistent.

Content

Scanner excerpt · SKILL.md (reported line 315)May include surrounding context.

bash
   source "<env.sh path>"
   # Substitute "abort" or "error":
   sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="abort"/' "$_STATE_DIR/env.sh" && rm -f "$_STATE_DIR/env.sh.bak"
  1. Run the Phase 4.4.5 telemetry epilogue. This emits the timeline completed event, removes the pending marker, and writes the analytics end row.
  2. Leave $_STATE_DIR intact (state.jsonl, TASKS.md, results). Print: "Aborted. State preserved at <_STATE_DIR>. Re-run /gstack-orchestrate to resume, or 'rm -rf <_STATE_DIR>' to discard."

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

This is another instance of backup-file deletion based on a variable path. The repeated pattern itself is concerning because it multiplies opportunities for unexpected path resolution under malformed state conditions.

Content

Scanner excerpt · SKILL.md (reported line 423)May include surrounding context.

md
- A) Approve and dispatch
- B) Refine (user describes changes; you regenerate TASKS.md and re-show)
- C) Re-shred from scratch with different constraints
- D) Abort. Set `_OUTCOME=abort` in env.sh (`sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="abort"/' "$_STATE_DIR/env.sh" && rm -f "$_STATE_DIR/env.sh.bak"`), run the Phase 4.4.5 epilogue, then stop.

Only proceed on A.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

The same path-based deletion occurs in the wave-failure abort path. Because this code executes after subagent failures, the surrounding state may be less trustworthy, which slightly increases operational risk.

Content

Scanner excerpt · SKILL.md (reported line 675)May include surrounding context.

md
- A) Dispatch a fix-up subagent (`Agent` with `isolation: "worktree"`) for that task with the blocker as scope
- B) Re-shred the remaining tasks (regenerate TASKS.md from this wave forward)
- C) Abort. Set `_OUTCOME=abort` in env.sh (`sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="abort"/' "$_STATE_DIR/env.sh" && rm -f "$_STATE_DIR/env.sh.bak"`), run the Phase 4.4.5 epilogue, then stop.

The orchestrator does NOT fix the failure itself.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

This cleanup command appears in the unrecoverable suite-failure path and carries the same variable-path deletion risk. Exceptional paths are especially important to harden because they may be reached when intermediate files are malformed or partially written.

Content

Scanner excerpt · SKILL.md (reported line 717)May include surrounding context.

$TEST_CMD && $LINT_CMD

text

If it still fails after the fix-up cherry-pick, ask the user via `AskUserQuestion`: A) dispatch another fix-up (max 2 retries per wave), B) abort. Do not loop indefinitely. On B (this is unrecoverable, not user-driven), set `_OUTCOME=error` in env.sh (`sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="error"/' "$_STATE_DIR/env.sh" && rm -f "$_STATE_DIR/env.sh.bak"`), run the Phase 4.4.5 epilogue, then stop.

### 3.5 Checkpoint + emit wave_completed (telemetry)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

The review-abort path repeats the same deletion primitive. Repetition across phases shows a systemic pattern rather than an isolated mistake, so the issue is credible despite each individual deletion being narrow.

Content

Scanner excerpt · SKILL.md (reported line 781)May include surrounding context.

md
1. Dispatch one cleanup subagent (`Agent` with `isolation: "worktree"`) with the review feedback as scope.
2. After it returns, cherry-pick its commit (read from `$_STATE_DIR/results/cleanup-1.json`) onto `$_BRANCH`.
3. Re-invoke `Skill({skill: "review"})`.
4. If issues remain, repeat once more (cleanup-2). After 2 cleanup passes, do NOT loop further. Use `AskUserQuestion`: A) ship anyway with known issues, B) abort (preserve state). On B, set `_OUTCOME=error` in env.sh (`sed -i.bak 's/^export _OUTCOME=.*/export _OUTCOME="error"/' "$_STATE_DIR/env.sh" && rm -f "$_STATE_DIR/env.sh.bak"`), run the Phase 4.4.5 epilogue, then stop. (On A, treat as success — preamble's `_OUTCOME=success` default carries through.)

### 4.2 QA / suite

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
88% confidence
Finding

The epilogue removes a pending marker in the user's home directory using a session-derived filename. While the session ID format is internally generated, deleting files in a shared global directory based on dynamic names creates a tampering and accidental-deletion risk if naming assumptions ever change.

Content

Scanner excerpt · SKILL.md (reported line 831)May include surrounding context.

md
_TEL_END=$(date +%s)
_TEL_DUR=$(( _TEL_END - ${_TEL_START:-$_TEL_END} ))
rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true

# Timeline: skill completed (local-only). jq-built for safe JSON.
_TL_BR=$(git branch --show-current 2>/dev/null || echo unknown)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill conditionally transmits run metadata to a remote telemetry binary without an upfront warning in the public-facing skill description. Remote exfiltration of repository- and session-related metadata is more serious than local logging because users may not realize information leaves the machine.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
89% confidence
Finding

The skill removes the persisted tel-state shell script via a dynamic path in ~/.gstack/analytics. Because that file is later sourced, any weakness in filename handling or directory permissions could turn this persistence/cleanup flow into a tampering vector.

Content

Scanner excerpt · SKILL.md (reported line 852)May include surrounding context.

fi

Clean up the preamble's tel-state file. Don't fail the epilogue if it's missing.

[ -n "${_SESSION_ID:-}" ] && rm -f ~/.gstack/analytics/.tel-"$_SESSION_ID".sh 2>/dev/null || true

text

### 4.5 Handoff

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README's user-facing flow under-describes the operational impact of the skill, omitting prominent warnings that it will spawn subagents, create worktrees, cherry-pick commits onto the current branch, persist state under the home directory, and run the full test suite. Informed consent matters here because these actions materially change repository state and can consume significant local or CI-like resources.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documented voice triggers are broad enough that ordinary conversation like 'orchestrate the plan' or 'execute the plan' could unintentionally invoke a high-impact automation skill. In this skill's context, accidental activation is more dangerous than usual because it can dispatch parallel subagents, modify git state, cherry-pick commits, and run tests across the repository.

Content

No source excerpt is available for this finding.

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
80% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · README.md (reported line 95)May include surrounding context.

md
## Where to read more

- Full skill definition: `~/.claude/skills/gstack-orchestrate/SKILL.md`
- Sibling skills it composes with: `/autoplan`, `/plan-eng-review`, `/review`, `/qa`, `/ship`
- The Agent tool's `isolation: "worktree"` mode is what makes parallel commits safe

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The invocation phrases are broad enough to match ordinary user requests like 'execute the plan' or 'ship the plan', which can trigger a high-impact orchestration skill unexpectedly. Because this skill can spawn parallel agents, edit repositories, and later hand off to shipping, accidental activation materially increases the chance of unintended code changes and workflow execution.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 25)May include surrounding context.

md
allowed-tools:
  - Bash
  - Read
  - Write
  - Edit
  - Glob
  - Grep

Static analysis

No suspicious patterns detected.