forge@0.17.0
VERIFIED· install onlyPublisher claims: "Multi-model coding with a reviewer that reads the code: plan, build in parallel worktrees, review every real diff, merge only what passes." Observed in sandbox: no network, touches nothing outside the project, writes no memory.
Coverage
Nothing executable in the bundle ran; the trace covers the install step only.- Tested
- every file read, file written and host contacted by what ran
- Not tested
- use of the skill by an agent
Is [email protected] safe to install?
KillerSkills ran it in the KillerSkills honeypot sandbox (1 scenario; nothing executable in the bundle ran; the trace covers the install step only) on 2026-11-12 and scored it 84/100 (Verified). In what ran, nothing we could detect went wrong: no undeclared network egress, no credential reads, no persistent instruction writes. What it does with a real credential was not observed; the static findings and the publisher carry the rest of the score. Summary: no network, touches nothing outside the project, writes no memory.
Behavior trace
Honeypot run · 0 s · 1 scenarios · 0 deviationsStatic findings
subprocess.run(cmd, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=10)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.if [ -n "${hpid:-}" ] && kill -0 "$hpid" 2>/dev/null; thenFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.pkill -TERM -P "$hpid" 2>/dev/null; kill -TERM "$hpid" 2>/dev/nullFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.sleep 1; kill -s KILL -- "-$hpid" 2>/dev/nullFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.planned = subprocess.run(['bash', str(SKILL / 'scripts' / 'forge-parallel.sh'), 'plan', str(new['plan']),Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.run = subprocess.run([sys.executable, script, 'gate', gate, value],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.rc = subprocess.run(command.split(), stdin=subprocess.DEVNULL).returncodeFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.top-level `--planner` as `--fractal-planner`; otherwise each task's initial root modelFix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct.return subprocess.run(['git', '-C', str(repo), *args], input=data, capture_output=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.[ "${GUARD_ON:-0}" != 1 ] || kill -s TERM -- "-$hpid" 2>/dev/nullFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.done = subprocess.run(base + ['--spec', spec, '--role', role], capture_output=True, text=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.out = subprocess.run(['git', '-C', str(repo), *args], capture_output=True, text=True, stdin=subprocess.DEVNULL)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.[ -z "${tpid:-}" ] || kill -TERM "$tpid" 2>/dev/nullFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.out = subprocess.run(['git', '-C', path, 'rev-parse', '--show-toplevel'],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.( sleep $(( limit + 10 )); kill -KILL "$pid" 2>/dev/null ) >/dev/null 2>&1 &Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.res = subprocess.run(cmd, cwd=cwd, input=stdin, capture_output=True, text=True, env=env, timeout=120)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.stopping.append((name, role, subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.FORGE_JEV=off is a hard kill switch and wins over every other setting, and a repo'sFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.local = subprocess.run(['git', '-C', str(repo), 'rev-parse', '--verify', '--quiet', 'refs/heads/' + head],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.kill -TERM -- "-$group" 2>/dev/null || { termed=0; kill -TERM "$group" 2>/dev/null; }Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.# default 20, plus a kill 10 s later), never changes the caller's exit code, logs its errors to theFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.kill -USR1 "$shadow_pid" 2>/dev/null || trueFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.result = subprocess.run(['git', '-C', str(cwd), *args], capture_output=True)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# on after every level (run flags, the kill switch and the privacy floor included) andFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.# first time: FORGE_JEV=off is a hard kill switch that wins over everything, and untilFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.[ "$ATTR_STOP" = 1 ] && kill -TERM "$ATTR_CHILD" 2>/dev/nullFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.out = subprocess.run(['git', '-C', str(start), 'rev-parse', '--show-toplevel'], capture_output=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.out = subprocess.run(['git', '-C', checkout, 'ls-files', '-z'], capture_output=True, check=True).stdoutFix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.trap 'ATTR_STOP=1; [ -n "$ATTR_CHILD" ] && kill -TERM "$ATTR_CHILD" 2>/dev/null' TERM INTFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.STATE['child'] = subprocess.Popen(argv, stdin=subprocess.DEVNULL, stdout=log, stderr=subprocess.STDOUT,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.process = subprocess.Popen(command, cwd=cwd, stdin=subprocess.DEVNULL,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.out = subprocess.run([ps, '-p', str(pid), '-o', field + '='], stdout=subprocess.PIPE,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# Also kill descendants that closed their pipes before the parent exited.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.[ "$ATTR_STOP" = 1 ] && kill -TERM "$ATTR_CHILD" 2>/dev/nullFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.out = subprocess.run([ps, '-axo', 'pid=,pgid=,stat=,command='],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.run(git_cmd(*args), capture_output=True, env=git_env(), timeout=timeout)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.pkill -P "$watcher" 2>/dev/null; kill "$watcher" 2>/dev/null; wait "$watcher" 2>/dev/nullFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# `on` marks the ones no task covers pending in plan-gates.json; the send-back file belowFix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.done = subprocess.run(['git', '--no-optional-locks', '-C', repo, *args], capture_output=True, text=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(['/bin/bash', str(DISPATCH), 'doctor', '--spec', spec, '--role', 'qa', *flags],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.flags, the kill switch, the privacy floor and a missing key all count. A gate that cannot answer behaves asFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.while kill -0 -- "-$group" 2>/dev/null || { [ "$termed" = 0 ] && kill -0 "$group" 2>/dev/null; }; doFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.# and SIGUSR1's default action would kill a launcher that is still preparing.Fix: Rename the tool with a prefix unique to your server.result = subprocess.run([sys.executable, ROUTE, 'attempt-cap', '--plan', str(plan), '--task', name],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.[ "$ATTR_STOP" = 1 ] && kill -TERM "$ATTR_CHILD" 2>/dev/nullFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.return 1 if subprocess.run(argv, cwd=repo, stdin=subprocess.DEVNULL).returncode else 0Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen(argv, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.done = subprocess.run(command, shell=True, cwd=str(cwd), capture_output=True, text=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(['/bin/bash', script, '_prepare_retry', str(plan), name, '--resume'])Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen(command, cwd=str(state), stdin=subprocess.DEVNULL, stdout=out, stderr=out,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.done = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.trap 'stopped=1; [ -n "$job" ] && kill -TERM "$job" 2>/dev/null' TERM INTFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.out = subprocess.run(['/bin/bash', str(DISPATCH), 'qa', spec, '--run-dir', tmp, '--prompt-file',Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen(command, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen(git_cmd('--git-dir=' + gitdir, 'archive', '--format=tar', sha),Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.out = subprocess.run([ps, '-axo', 'pid=,ppid=,stat=,lstart=,command='], stdout=subprocess.PIPE,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.upstream = subprocess.run(['git', '-C', str(repo), 'for-each-ref', '--format=%(upstream)', 'refs/heads/' + head],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.run(['/bin/bash', '-c', 'source "$1"; shift; "$@"', '_', str(ARTIFACT), function, *args],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(['/bin/bash', script, '_merge', str(plan), name])Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(['/bin/bash', script, '_prepare_retry', str(plan), name])Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run(build(title, clean(describe(event))), stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.echo 'forge: installed with npm; update with: npm install -g @giamme/forge@latest && forge install' >&2; return 2 ;;Fix: Pin the exact version (`[email protected]`, `==1.2.3`) so every install gets the bytes that were reviewed.out = subprocess.run(['git', '-C', str(source), *args], capture_output=True, text=True,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# A runner script that was never chmod +x is still the project's realFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.listed = subprocess.run(['git', '-C', str(repo), 'ls-files', '-z'],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.proc = subprocess.Popen(['/bin/bash', '-c', lane['command']], cwd=self.checkout,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.out = subprocess.run(['git', '-C', str(repo), 'ls-files', '-z'],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."""Rewrite lanes.json. State changes force it; output only marks it due."""Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.out = subprocess.run(['git', '-C', str(repo), '-c', 'core.quotePath=false', 'log',Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.out = subprocess.run(['git', '-C', str(Path(anchor).parent), 'rev-parse', '--show-toplevel'],Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.run(['git', '-C', str(repo), 'ls-files', '--error-unmatch', '--', str(path)], stdin=subprocess.DEVNULL,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.done = subprocess.run(argv_or_cmd, shell=shell, cwd=cwd, env=hook_env(event), stdin=subprocess.DEVNULL,Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.Cost to the agent
Tokens estimated at four characters each. Skills load their instruction text when triggered; the figure is what that costs.
Known vulnerabilities
No advisories in OSV for @giamme/forge@0.17.0 as of 2d ago. This is the package itself, not its dependencies.