Skip to content

Guard waves 3-5: container, remote, Windows and wrapper passthrough; blind held-out-6 to 9 - #1993

Merged
remigiusz-antczak merged 1 commit into
mainfrom
land/guard-w5c
Oct 25, 2026
Merged

remigiusz-antczak merged 1 commit into
mainfrom
land/guard-w5c

Conversation

@remigiusz-antczak

Copy link
Copy Markdown
Collaborator

This supersedes #1991, adding guard wave 5 and a third blind corpus. The destructive guard now sees commands hidden inside containers, remote shells, sqlite3, watch, parallel and Windows shells. On a corpus frozen before any of these rules existed, it blocks 48 of 60 dangerous commands, against 14 for hooks-mastery and 12 for safety-net.

Held-out-8 (blind, 60 dangerous / 60 benign) Blocked Benign blocked
Perun guard, wave 5 (27d1c7d63) 48/60 1/60
Perun guard, this PR after review fixes 49/60 1/60
Perun guard, #1991 (7503ea3) 41/60 2/60
claude-code-hooks-mastery, ported 14/60 7/60
claude-code-safety-net, ported subset 12/60 (2 unported) 0/60
  • Held-out-9, a fourth blind corpus, written after these rules were final. It was pushed before scoring (prereg/heldout9, ffb22e7):

    • this PR: 55/60 blocked, 0/60 benign blocked;
    • main: 48/60 and 0/60;
    • hooks-mastery: 8/60 and 2/60;
    • safety-net: 9/60 and 0/60, with 1 row unported.

    The five misses are aws kms schedule-key-deletion, a clickhouse DROP TABLE, gem uninstall -aIx, diskutil apfs deleteContainer and tmutil delete.

  • Preregistered. Held-out-8 was pushed before scoring (prereg/heldout8, e451111).

  • Why 49 differs from 48. The fixes behind 49/60 came from an independent review that never saw the corpus. The extra block is a PowerShell Get-ChildItem | Remove-Item pipeline.

  • Remaining misses (11). These are the leads for wave 6: tmutil delete, launchctl bootout chained with rm, perl remove_tree, make clean ROOT=/, cdk, doctl, flyctl, heroku and clickhouse deletes, hg strip, and an IFS split. The one false positive is find ./dist -name '*.map' -delete.

  • Held-out-6 and 7 are now in-sample. The wave-5 rules were written against their misses. Their blind rows are pinned by test_security_gates_heldout{6,7}_blind.py:

    • held-out-6: 45/60 blind, 2/60 benign blocked;
    • held-out-7: 51/60 blind, 1/60 benign blocked.

Rule changes, waves 3 and 4 (as in #1991):

  • Inner command checked: docker, podman and nerdctl exec/run; kubectl exec|run|debug; oc exec|debug|rsh; sqlite3 .shell, .system and .read |.
  • Now blocked:
    • >> and tee onto system paths;
    • nested decode-then-execute;
    • the /private/* aliases for rm;
    • $VAR/.. write targets.

Rule changes, wave 5:

  • Wrappers:
    • watch with any flags and a quoted or unquoted command;
    • parallel with a quoted command string, ::: or ::::;
    • nohup;
    • xargs -0 rm.
  • Windows:
    • del and rd of drive roots and system directories;
    • format, including format.com;
    • diskpart;
    • bcdedit /delete;
    • reg delete with the hive in any position;
    • wmic ... delete and call format;
    • PowerShell Remove-Item -Recurse with flags in any order or fed by a pipeline.
  • Secrets, VCS and data:
    • vault deletes;
    • gh api -X DELETE;
    • glab deletes;
    • mongosh deleteMany;
    • reflog expire plus gc;
    • cp onto system files;
    • openssl enc piped to a shell;
    • kubectl exec ... bash -c with a destructive inner command.
  • Speed: the base64 scan went from 0.68 s to 0.04 s on the held-out-4 timing blob.

Review history:

  • Wave 5 review: 3 🔴, all fixed: quoted watch and parallel commands, and Windows drive-root deletes.
  • Re-review: 1 🔴, also fixed (watch -d and --interval before the command).
  • Final review: 1 🔴, fixed: format c:\ /q slipped past because of the trailing backslash. del of %SystemRoot%, %windir% and \Windows paths is now blocked, and extension-scoped del *.tmp in the current directory is allowed.
  • Folded into wave 6 (🟡):
    • kubectl run --overrides privileged pods;
    • sqlite ATTACH of non-system paths;
    • ln -sf and rsync onto /etc;
    • vault lease and token revoke;
    • git reflog delete;
    • chroot -u;
    • mongosh remove and deleteOne;
    • del wildcards that are still allowed: del *.* in the current directory, ..\ paths, %USERPROFILE%, non-system drives, and *.dll or *.sys under System32. Main blocks none of these either;
    • false positives on find . -prune | xargs -0 rm, on cp to /etc/*.bak and on del /s /q *.log.

#1991 failed CI on test_audit_skills because guard edits moved four finding fingerprints. All four are lines where the guard quotes the commands it blocks, and they are triaged with that reason.

Local gates:

  • test_security_gates*.py: 16/16. test-destructive-guard.sh: 16/16. test_audit_skills: pass.
  • ci-tests.d: pass, except three scripts that cannot run in the local sandbox: run-ledger (lsof), prepush-ci-parity (200 s timeout) and bench-check (needs origin/main).
  • Size-ratchet: ok. bench_check: clean. git diff --check: clean. Privacy: clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_014QNFFPWVcPUbeuvwM5fk2Z

…blind held-out-6, 7 and 8

The destructive guard now checks the inner command of docker, podman, nerdctl, kubectl and oc exec/run/debug, sqlite3 dot-commands, watch, parallel, nohup and xargs -0, and blocks Windows and PowerShell drive deletes and formats, system-file writes, nested decode-exec, and secrets, cloud and VCS deletes.

Held-out-8 (prereg/heldout8 e451111, pushed before scoring): wave-5 guard 48/60 blocked, 1/60 benign blocked; 49/60 after independent-review fixes that never saw the corpus; the guard at 7503ea3 41/60 (FP 2); hooks-mastery 14/60 (FP 7); safety-net 12/60 (FP 0, 2 unported). Held-out-6 and 7 were blind at 45/60 and 51/60, and are now in-sample with their blind rows pinned. The audit-skills triage covers four guard lines that quote the commands it blocks.

Tests: 16/16 security gate scripts, test_audit_skills, test-destructive-guard 16/16, ci-tests.d pass (run-ledger, prepush-ci-parity and bench-check skipped locally: sandbox lsof, 200 s timeout, no origin/main in the clone), size-ratchet, bench_check, diff-check

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QNFFPWVcPUbeuvwM5fk2Z
@remigiusz-antczak
remigiusz-antczak merged commit 49162c7 into main Oct 25, 2026
1 check passed
@remigiusz-antczak
remigiusz-antczak deleted the land/guard-w5c branch October 25, 2026 05:18
remigiusz-antczak added a commit that referenced this pull request Oct 25, 2026
…-out-9 (#1994)

The destructive guard now blocks tmutil delete, cdk/cdktf/sst destroy, doctl/flyctl/heroku deletes, hg strip/purge, make clean with a root variable, `set -- rm ...; "$@"` (also IFS-split), aws kms schedule-key-deletion, gem uninstall of everything, diskutil apfs delete/erase, kubectl run with hostPID/privileged/hostPath, sqlite3 `.read |sh`, ln/rsync onto a system path, vault lease/token revoke and policy delete, git reflog delete, chroot -u, mongosh remove/deleteOne, clickhouse DROP, wmic call create/uninstall, reg add/copy/save on HKLM, rm -r under /Library and other system dirs, and Windows `del` of system files, `..` paths and a bare `*` or `*.*`. Allowed stay: find ./dist -name '*.map' -delete, cp to /etc/*.bak, git reflog expire with a non-now age, del /s /q *.log in the cwd.

Held-out-9 (prereg/heldout9 ffb22e7, pushed before scoring): #1993 guard 55/60 blocked, 0/60 benign blocked; main before #1993 48/60, 0/60; hooks-mastery 8/60 (FP 2); safety-net 9/60 (FP 0, 1 unported). Held-out-8 and 9 are in-sample at 60/60, FP 0 after this wave; their blind rows are pinned in new *_blind tests.

Tests: 20/20 security gate scripts, test-destructive-guard 16/16, test_audit_skills 11/11, ci-tests.d all pass (run-ledger, prepush-ci-parity, bench-check skipped), size-ratchet ok, test-ci-gates 162 PASS with 4+ dcr-gates opt-in FAIL from sandbox EPERM on port bind (surface_check selftest), git diff --check clean


Claude-Session: https://claude.ai/code/session_014QNFFPWVcPUbeuvwM5fk2Z

Co-authored-by: Remigiusz Antczak <remigiusz@antczak.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant