Back to skill

Security audit

foreman

Security checks for vulnerabilities and agentic risk

Overview

The skill is a clearly disclosed background coding-agent dispatcher with real operational risk, but its sensitive behavior is purpose-aligned and substantially scoped.

Install only if you intend to send repository work to background agent backends. Use dedicated low-limit API keys, avoid global shell exports, keep .foreman gitignored, review any FOREMAN_PROBE_<NAME> command before setting it, and prefer the caged worker plus network allowlisting for sensitive repositories.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **Probes backends before dispatch** (`backend-health.sh`, all probes listed in its header): `claude auth status` and `cursor-agent status` read local login st

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documentation describes capabilities that include reading environment variables, writing files in the repository and user state directories, probing backends over the network, and optionally launching a Docker-based worker that can access a networked API key. However, the skill declares no explicit tool scope or allowed-tools/permissions boundary, so a host may expose broader capabilities than the user expects. In a skill that dispatches work to external backends and handles credentials, missing explicit scope increases the chance of unintended data exposure or misuse if the runtime grants more authority than the documented minimum.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · backend-health.sh (reported line 31)May include surrounding context.

sh
# Built-in probes, chosen by backend name, and what each one costs:
#   claude | opus | sonnet   `claude auth status` — local read, no request, no tokens
#   cursor                   `cursor-agent status` — local login check, no conversation request
#   deepseek                 GET https://api.deepseek.com/user/balance with $DEEPSEEK_API_KEY — no tokens.
#                            The key is sent only to that endpoint. If the variable isn't set, the result is `unchecked`.
#   codex                    one minimal `codex exec` call — this one spends a request, which is why its failures always cool down
# A backend with neither a built-in nor a FOREMAN_PROBE_<NAME> probe reports `unchecked`: pick still uses it, but says so.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · backend-health.sh (reported line 147)May include surrounding context.

sh
# Built-in probes, chosen by backend name, and what each one costs:
#   claude | opus | sonnet   `claude auth status` — local read, no request, no tokens
#   cursor                   `cursor-agent status` — local login check, no conversation request
#   deepseek                 GET https://api.deepseek.com/user/balance with $DEEPSEEK_API_KEY — no tokens.
#                            The key is sent only to that endpoint. If the variable isn't set, the result is `unchecked`.
#   codex                    one minimal `codex exec` call — this one spends a request, which is why its failures always cool down
# A backend with neither a built-in nor a FOREMAN_PROBE_<NAME> probe reports `unchecked`: pick still uses it, but says so.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · foreman-cworker.sh (reported line 86)May include surrounding context.

sh
# Built-in probes, chosen by backend name, and what each one costs:
#   claude | opus | sonnet   `claude auth status` — local read, no request, no tokens
#   cursor                   `cursor-agent status` — local login check, no conversation request
#   deepseek                 GET https://api.deepseek.com/user/balance with $DEEPSEEK_API_KEY — no tokens.
#                            The key is sent only to that endpoint. If the variable isn't set, the result is `unchecked`.
#   codex                    one minimal `codex exec` call — this one spends a request, which is why its failures always cool down
# A backend with neither a built-in nor a FOREMAN_PROBE_<NAME> probe reports `unchecked`: pick still uses it, but says so.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script executes administrator-supplied probe strings with sh -c, which allows arbitrary shell metacharacters, command chaining, expansion, and exfiltration behavior. Because probe definitions come from environment variables and this skill already interacts with credentials and backend state, a malicious or mistaken probe can run arbitrary code on the host under the user's privileges.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
83% confidence
Finding

The skill launches background handoff runs that persist task context and repository content in ~/.handoff/tasks/..., creating durable artifacts outside the repo's normal controls. That persistence can expose sensitive code, prompts, or operational metadata to other local processes/users and increases the chance of stale or cross-task data being reused incorrectly.

Content

Scanner excerpt · dispatch.md (reported line 32)May include surrounding context.

md
BE=$(bash <skill-dir>/backend-health.sh pick) || { echo "no usable backend in the pool — stop and report"; exit 1; }
WT=$(bash <skill-dir>/worktree-setup.sh "$(pwd)" <slug>) || { echo "worktree setup failed — see the error above"; exit 1; }

handoff new --backend "$BE" --slug <slug> --write <<'__HF_EOF__'
[full work order]
__HF_EOF__
handoff run --backend "$BE" --cwd "$WT" ~/.handoff/tasks/<RUN_ID>.prompt.md   # run in background

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
90% confidence
Finding

Using a worker configuration that 'runs commands and edits files without asking anyone' materially increases risk because the agent can perform unintended or harmful actions before a human reviews the result. The surrounding acceptance workflow reduces merge risk but does not prevent damage during task execution, especially if secrets, network access, or checkout isolation are imperfect.

Content

Scanner excerpt · dispatch.md (reported line 68)May include surrounding context.

md
### Cursor through handoff

No handoff code change is needed. handoff deep-merges per-backend fields over the type defaults (lists are replaced wholesale), and `command`, `session_flags`, `continue_id_flags` and `resume_flags` are all overridable — so a backend of `type: claude` with `command: cursor-agent` works. `cursor-agent` has no `--dangerously-skip-permissions` or `--append-system-prompt`: use `--force` to skip confirmations, and put the system prompt into the prompt body itself. **`--force` means the worker runs commands and edits files without asking anyone** — that is what makes background dispatch possible, and it is also why it must only ever run with `--cwd` pointing at a task worktree, never your main checkout, and why every delivery still goes through intake before it is merged. The same holds for any backend configured to skip permission prompts. Unverified: whether the model weighs an inlined system prompt the same as a separate system layer — only that it is sent and followed.

### Caged dispatch (optional; for sensitive repos or when you want a hard blast radius)

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
90% confidence
Finding

Using a worker configuration that 'runs commands and edits files without asking anyone' materially increases risk because the agent can perform unintended or harmful actions before a human reviews the result. The surrounding acceptance workflow reduces merge risk but does not prevent damage during task execution, especially if secrets, network access, or checkout isolation are imperfect.

Content

Scanner excerpt · dispatch.md (reported line 68)May include surrounding context.

md
### Cursor through handoff

No handoff code change is needed. handoff deep-merges per-backend fields over the type defaults (lists are replaced wholesale), and `command`, `session_flags`, `continue_id_flags` and `resume_flags` are all overridable — so a backend of `type: claude` with `command: cursor-agent` works. `cursor-agent` has no `--dangerously-skip-permissions` or `--append-system-prompt`: use `--force` to skip confirmations, and put the system prompt into the prompt body itself. **`--force` means the worker runs commands and edits files without asking anyone** — that is what makes background dispatch possible, and it is also why it must only ever run with `--cwd` pointing at a task worktree, never your main checkout, and why every delivery still goes through intake before it is merged. The same holds for any backend configured to skip permission prompts. Unverified: whether the model weighs an inlined system prompt the same as a separate system layer — only that it is sent and followed.

### Caged dispatch (optional; for sensitive repos or when you want a hard blast radius)

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 · dispatch.md (reported line 104)May include surrounding context.

md
- Task state at `.foreman/<task_id>.json`:
  `{task_id, attempt_id, handoff_run_id, backend, worktree, branch, dispatched_at, deadline_at, rework_count, repair_rounds, error_fingerprint, backend_fallback, status}`
  `handoff_run_id` is the basename of the `.prompt.md` path that `handoff new` prints (that command pre-allocates the run and echoes the path, not a bare id). Write it at dispatch time and update it with `attempt_id` on every redispatch — the batch → task → delivery audit chain closes through that field.
  `worktree` / `branch` are what `worktree-setup.sh` returned and created; intake runs against those two fields instead of guessing paths.
- Batch state at `.foreman/batch.json`: `{batch_id, members[], integration_sha: null, total_rounds: 0}`

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · fleet-check.sh (reported line 97)May include surrounding context.

sh
ok "no ANTHROPIC_API_KEY in the shell"
fi
case "${ANTHROPIC_BASE_URL:-}" in
  ""|https://api.anthropic.com|https://api.anthropic.com/) ok "no ANTHROPIC_BASE_URL leak" ;;
  *) bad "ANTHROPIC_BASE_URL is set to a non-default value (not printed here — it can carry a token)" \
        "remove it from your shell rc — it silently reroutes every agent session on this machine to another backend" ;;
esac

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 · worktree-setup.sh (reported line 2)May include surrounding context.

sh
#!/bin/bash
# foreman dispatch helper: create an isolated git worktree for one task and print its absolute path on stdout.
#
# Why a script instead of "remember to run git worktree add": for a long time "one git worktree per task" was an
# invariant written in prose, while the copy-paste dispatch example never showed how to create one or pass --cwd to

Tool Parameter Abuse

Low
Category
Tool Misuse
Confidence
15% 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 · dispatch.md (reported line 80)May include surrounding context.

md
docker build -t foreman-worker - <<'DOCKERFILE'
FROM node:22.19-slim@sha256:4a4884e8a44826194dff92ba316264f392056cbe243dcc9fd3551e71cea02b90
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates ripgrep \
    && rm -rf /var/lib/apt/lists/* \
    && npm i -g @anthropic-ai/claude-code@2.1.270 \
    && useradd -m worker
USER worker

Tool Parameter Abuse

Low
Category
Tool Misuse
Confidence
15% 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 · dispatch.md (reported line 80)May include surrounding context.

md
docker build -t foreman-worker - <<'DOCKERFILE'
FROM node:22.19-slim@sha256:4a4884e8a44826194dff92ba316264f392056cbe243dcc9fd3551e71cea02b90
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates ripgrep \
    && rm -rf /var/lib/apt/lists/* \
    && npm i -g @anthropic-ai/claude-code@2.1.270 \
    && useradd -m worker
USER worker

Tool Parameter Abuse

Low
Category
Tool Misuse
Confidence
15% 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 · dispatch.md (reported line 80)May include surrounding context.

md
docker build -t foreman-worker - <<'DOCKERFILE'
FROM node:22.19-slim@sha256:4a4884e8a44826194dff92ba316264f392056cbe243dcc9fd3551e71cea02b90
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates ripgrep \
    && rm -rf /var/lib/apt/lists/* \
    && npm i -g @anthropic-ai/claude-code@2.1.270 \
    && useradd -m worker
USER worker

Chaining Abuse

Low
Category
Tool Misuse
Confidence
15% 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 · dispatch.md (reported line 80)May include surrounding context.

md
docker build -t foreman-worker - <<'DOCKERFILE'
FROM node:22.19-slim@sha256:4a4884e8a44826194dff92ba316264f392056cbe243dcc9fd3551e71cea02b90
RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates ripgrep \
    && rm -rf /var/lib/apt/lists/* \
    && npm i -g @anthropic-ai/claude-code@2.1.270 \
    && useradd -m worker
USER worker

Static analysis

No suspicious patterns detected.