cc-safe-setup 29.7.0 → 30.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +72 -19
- package/.claude-plugin/plugin.json +1 -1
- package/CONTRIBUTING.md +7 -2
- package/COOKBOOK.md +50 -46
- package/LICENSE +21 -0
- package/MIGRATION.md +8 -8
- package/README.md +419 -512
- package/SAFETY_CHECKLIST.md +15 -7
- package/SERVICES.md +194 -0
- package/SETTINGS_REFERENCE.md +236 -17
- package/SKILL.md +5 -5
- package/TROUBLESHOOTING.md +35 -14
- package/action.yml +12 -4
- package/audit/README.md +84 -0
- package/audit/audit-checklist.md +152 -0
- package/audit/boundary-selftest.sh +85 -0
- package/audit/boundary.sh +123 -0
- package/audit/count-hooks.py +42 -0
- package/audit/find-dead-hooks.sh +82 -0
- package/audit/find-unfirable-rules.sh +142 -0
- package/audit/fire.sh +97 -0
- package/audit/selftest.sh +42 -0
- package/audit/unfirable-selftest.sh +81 -0
- package/audit-web/index.html +9 -9
- package/examples/README.md +54 -17
- package/examples/account-billing-log.sh +98 -0
- package/examples/account-routing-preflight.sh +123 -0
- package/examples/agent-sdk-credit-pool-monitor.sh +145 -0
- package/examples/agent-view-quota-decrement.sh +32 -0
- package/examples/agent-view-quota-warn.sh +94 -0
- package/examples/agents-md-edit-drift-warner.sh +223 -0
- package/examples/agents-md-loader.sh +160 -0
- package/examples/agents-md-sync-checker.sh +102 -0
- package/examples/ai-slop-punctuation-arrest.sh +210 -0
- package/examples/allowlist.sh +70 -10
- package/examples/always-allow-pattern-suggester.sh +125 -0
- package/examples/ansible-vault-guard.sh +2 -1
- package/examples/anthropic-base-url-guard.sh +76 -0
- package/examples/api-busyloop-guard.sh +123 -0
- package/examples/api-endpoint-guard.sh +12 -0
- package/examples/api-key-in-url-guard.sh +17 -1
- package/examples/api-rate-limit-guard.sh +36 -1
- package/examples/api-rate-limit-tracker.sh +12 -0
- package/examples/articulated-scope-capture.sh +101 -0
- package/examples/askuserquestion-autonomy-gate.sh +102 -0
- package/examples/attachment-traversal-guard.sh +118 -0
- package/examples/aup-block-pattern-logger.sh +161 -0
- package/examples/aup-false-positive-helper.sh +124 -0
- package/examples/aup-large-tool-output-warner.sh +282 -0
- package/examples/aup-retry-loop-guard.sh +229 -0
- package/examples/auth-expiry-reminder.sh +157 -0
- package/examples/auth-macos-sleep-detector.sh +185 -0
- package/examples/auth-path-detector.sh +171 -0
- package/examples/auth-status-checker.sh +157 -0
- package/examples/authorized-reconfirmation-detector.sh +195 -0
- package/examples/auto-approve-build.sh +39 -0
- package/examples/auto-approve-cargo.sh +31 -1
- package/examples/auto-approve-docker.sh +35 -0
- package/examples/auto-approve-git-read.sh +37 -14
- package/examples/auto-approve-go.sh +30 -1
- package/examples/auto-approve-gradle.sh +29 -1
- package/examples/auto-approve-make.sh +29 -1
- package/examples/auto-approve-maven.sh +29 -1
- package/examples/auto-approve-python.sh +41 -1
- package/examples/auto-approve-readonly-tools.sh +1 -0
- package/examples/auto-approve-readonly.sh +110 -33
- package/examples/auto-approve-ssh.sh +30 -1
- package/examples/auto-approve-test.sh +44 -0
- package/examples/auto-checkpoint.sh +1 -1
- package/examples/auto-compact-prep.sh +0 -0
- package/examples/auto-git-checkpoint.sh +0 -0
- package/examples/auto-mode-safe-commands.sh +53 -1
- package/examples/auto-mode-safety-enforcer.sh +151 -4
- package/examples/auto-push-session-branch.sh +22 -0
- package/examples/aws-production-guard.sh +13 -1
- package/examples/aws-region-guard.sh +1 -1
- package/examples/background-cost-launch-guard.sh +82 -0
- package/examples/background-task-guard.sh +12 -0
- package/examples/backup-before-refactor.sh +0 -0
- package/examples/banned-command-guard.sh +12 -0
- package/examples/bash-allowlist-secondary-check.sh +157 -0
- package/examples/bash-domain-allowlist.sh +12 -0
- package/examples/bash-fanout-bounded-rewriter.sh +191 -0
- package/examples/bash-heuristic-approver.sh +112 -10
- package/examples/bash-project-fence.sh +194 -0
- package/examples/bash-safety-auto-deny.sh +12 -0
- package/examples/bash-secret-output-detector.sh +44 -3
- package/examples/bash-trace-guard.sh +12 -0
- package/examples/bashrc-safety-check.sh +0 -0
- package/examples/bg-permission-prompt-warner.sh +182 -0
- package/examples/bg-task-cooldown-guard.sh +12 -0
- package/examples/binary-read-detector.sh +135 -0
- package/examples/binary-upload-guard.sh +12 -0
- package/examples/block-database-wipe.sh +35 -10
- package/examples/branch-name-check.sh +8 -3
- package/examples/branch-naming-convention.sh +0 -0
- package/examples/broad-find-guard.sh +12 -0
- package/examples/broad-prefix-session-trap-warner.sh +106 -0
- package/examples/bulk-file-delete-guard.sh +45 -0
- package/examples/bypass-mode-effective-verifier.sh +203 -0
- package/examples/cache-creation-drift-detector.sh +120 -0
- package/examples/cache-residue-detector.sh +195 -0
- package/examples/cache-tier-logger.sh +70 -0
- package/examples/cache-ttl-eviction-detector.sh +149 -0
- package/examples/cargo-publish-guard.sh +14 -1
- package/examples/case-insensitive-path-guard.sh +21 -2
- package/examples/case-sensitive-guard.sh +23 -2
- package/examples/cch-cache-guard.sh +0 -0
- package/examples/cch-sentinel-precommit-guard.sh +47 -0
- package/examples/check-abort-controller.sh +1 -1
- package/examples/check-accessibility.sh +0 -0
- package/examples/check-aria-labels.sh +0 -0
- package/examples/check-before-act-enforcer.sh +12 -0
- package/examples/check-charset-meta.sh +0 -0
- package/examples/check-cookie-flags.sh +0 -0
- package/examples/check-cors-config.sh +0 -0
- package/examples/check-csp-headers.sh +0 -0
- package/examples/check-csrf-protection.sh +0 -0
- package/examples/check-debounce.sh +1 -1
- package/examples/check-dependency-age.sh +0 -0
- package/examples/check-dependency-license.sh +0 -0
- package/examples/check-dockerfile-best-practice.sh +0 -0
- package/examples/check-error-boundaries.sh +0 -0
- package/examples/check-error-class.sh +1 -1
- package/examples/check-error-handling.sh +0 -0
- package/examples/check-error-logging.sh +1 -1
- package/examples/check-error-message.sh +0 -0
- package/examples/check-error-stack.sh +0 -0
- package/examples/check-favicon.sh +0 -0
- package/examples/check-git-hooks-compat.sh +0 -0
- package/examples/check-gitattributes.sh +0 -0
- package/examples/check-https-redirect.sh +0 -0
- package/examples/check-input-validation.sh +0 -0
- package/examples/check-lang-attribute.sh +0 -0
- package/examples/check-npm-scripts-exist.sh +0 -0
- package/examples/check-package-size.sh +0 -0
- package/examples/check-port-availability.sh +0 -0
- package/examples/check-promise-all.sh +1 -1
- package/examples/check-rate-limiting.sh +0 -0
- package/examples/check-return-types.sh +0 -0
- package/examples/check-semantic-versioning.sh +0 -0
- package/examples/check-suspense-fallback.sh +1 -1
- package/examples/check-test-exists.sh +0 -0
- package/examples/check-test-naming.sh +0 -0
- package/examples/check-timeout-cleanup.sh +1 -1
- package/examples/check-tls-version.sh +0 -0
- package/examples/check-unsubscribe.sh +1 -1
- package/examples/check-viewport-meta.sh +0 -0
- package/examples/check-worker-terminate.sh +1 -1
- package/examples/checkpoint-tamper-guard.sh +12 -0
- package/examples/chmod-guard.sh +12 -0
- package/examples/chown-guard.sh +24 -0
- package/examples/ci-workflow-guard.sh +6 -1
- package/examples/claim-verify-detector.sh +109 -0
- package/examples/claim-vs-caveat-checker.sh +77 -0
- package/examples/classifier-fallback-allow.sh +114 -40
- package/examples/claude-cache-gc.sh +1 -0
- package/examples/claude-code-version-pin-advisor.sh +183 -0
- package/examples/claude-md-reinjector.sh +129 -0
- package/examples/claude-md-size-monitor.sh +66 -0
- package/examples/claude-update-budget-guard.sh +123 -0
- package/examples/claude-update-smart.sh +113 -0
- package/examples/claudeignore-enforce-guard.sh +12 -0
- package/examples/claudemd-enforcer.sh +0 -0
- package/examples/claudemd-tool-prohibition.sh +128 -0
- package/examples/clear-command-confirm-guard.sh +32 -15
- package/examples/cli-config-pinning-detector.sh +162 -0
- package/examples/cliff-countdown-advisor.sh +96 -0
- package/examples/clipboard-secret-guard.sh +12 -0
- package/examples/closure-word-verify-gate.sh +150 -0
- package/examples/cloud-cli-guard.sh +39 -2
- package/examples/commit-all-scope-guard.sh +44 -0
- package/examples/commit-message-check.sh +1 -1
- package/examples/commit-message-quality.sh +6 -1
- package/examples/commitment-carry-forward-arrest.sh +361 -0
- package/examples/compact-alert-notification.sh +0 -0
- package/examples/compact-circuit-breaker.sh +72 -0
- package/examples/compact-dispatch-watchdog.sh +149 -0
- package/examples/completion-claim-without-verification-detector.sh +207 -0
- package/examples/composer-guard.sh +12 -0
- package/examples/compound-bash-permission-resolver.sh +156 -0
- package/examples/compound-command-allow.sh +1 -1
- package/examples/compound-command-deny-enforcer.sh +183 -0
- package/examples/compound-inject-guard.sh +12 -0
- package/examples/concurrent-edit-lock.sh +12 -0
- package/examples/conflict-marker-guard.sh +12 -0
- package/examples/consecutive-error-breaker.sh +0 -0
- package/examples/console-log-count.sh +1 -0
- package/examples/context-compact-advisor.sh +29 -2
- package/examples/context-length-budget.sh +69 -0
- package/examples/context-threshold-alert.sh +12 -0
- package/examples/context-usage-drift-alert.sh +41 -13
- package/examples/conversation-history-guard.sh +12 -0
- package/examples/core-file-protect-guard.sh +12 -0
- package/examples/cors-star-warn.sh +0 -0
- package/examples/cost-incident-self-audit.sh +162 -0
- package/examples/cowork-claude-md-load-checker.sh +100 -0
- package/examples/cowork-fuse-staleness-watcher.sh +140 -0
- package/examples/cowork-hook-absence-warner.sh +167 -0
- package/examples/cowork-model-picker-advisor.sh +115 -0
- package/examples/credential-exfil-guard.sh +65 -4
- package/examples/credential-file-cat-guard.sh +17 -1
- package/examples/cron-create-receipt.sh +112 -0
- package/examples/cron-modification-guard.sh +12 -0
- package/examples/cross-product-mcp-spawn-detector.sh +178 -0
- package/examples/cwd-project-boundary-guard.sh +0 -0
- package/examples/daemon-zombie-worker-surfacer.sh +118 -0
- package/examples/daily-cost-guard.sh +164 -0
- package/examples/daily-usage-tracker.sh +0 -0
- package/examples/dangerous-pip-flag-guard.sh +12 -0
- package/examples/db-connect-guard.sh +13 -1
- package/examples/denied-action-retry-guard.sh +12 -0
- package/examples/deny-bypass-detector.sh +12 -0
- package/examples/deny-rule-integrity-verifier.sh +181 -0
- package/examples/dependency-install-guard.sh +12 -0
- package/examples/deploy-guard.sh +14 -2
- package/examples/deploy-path-verify-guard.sh +12 -0
- package/examples/deployment-readback-gate.sh +135 -0
- package/examples/deployment-readback-gh-adapter.sh +247 -0
- package/examples/deployment-verify-guard.sh +25 -2
- package/examples/destructive-db-script-write-guard.sh +166 -0
- package/examples/destructive-migration-write-guard.sh +163 -0
- package/examples/diff-size-guard.sh +12 -0
- package/examples/disabled-feature-toggle-advisor.sh +88 -0
- package/examples/disk-partition-guard.sh +12 -0
- package/examples/dispatch-allowlist-preflight.sh +301 -0
- package/examples/dispatch-liveness-watchdog.sh +216 -0
- package/examples/dispatch-receipt.sh +174 -0
- package/examples/django-migrate-guard.sh +12 -0
- package/examples/dns-config-guard.sh +12 -0
- package/examples/docker-dangerous-guard.sh +12 -0
- package/examples/docker-volume-guard.sh +0 -0
- package/examples/dockerfile-latest-guard.sh +1 -0
- package/examples/dotenv-anthropic-key-billing-guard.sh +99 -0
- package/examples/dotenv-commit-guard.sh +12 -0
- package/examples/dotenv-read-guard.sh +12 -0
- package/examples/dotfile-protection-guard.sh +12 -0
- package/examples/dotnet-build-on-edit.sh +1 -1
- package/examples/drizzle-migrate-guard.sh +27 -2
- package/examples/echo-probe-spam-detector.sh +176 -0
- package/examples/edit-counter-test-gate.sh +12 -0
- package/examples/edit-error-counter.sh +1 -1
- package/examples/edit-guard.sh +12 -0
- package/examples/edit-old-string-validator.sh +12 -0
- package/examples/edit-quote-ambiguity-guard.sh +97 -0
- package/examples/edit-retry-loop-guard.sh +0 -0
- package/examples/edit-verify.sh +0 -0
- package/examples/env-inline-secret-guard.sh +14 -2
- package/examples/env-naming-convention.sh +0 -0
- package/examples/env-prod-guard.sh +0 -0
- package/examples/env-required-check.sh +0 -0
- package/examples/env-source-guard.sh +12 -0
- package/examples/env-var-check.sh +24 -1
- package/examples/ephemeral-container-detector.sh +147 -0
- package/examples/error-memory-guard.sh +12 -0
- package/examples/evidence-claim-gate.sh +187 -0
- package/examples/exploration-budget-guard.sh +89 -0
- package/examples/expo-eject-guard.sh +13 -0
- package/examples/extended-thinking-loop-guard.sh +139 -0
- package/examples/extended-thinking-resume-warning.sh +119 -0
- package/examples/extended-thinking-tool-use-mismatch-detector.sh +212 -0
- package/examples/fabricated-command-detector.sh +145 -0
- package/examples/false-disk-full-guard.sh +63 -0
- package/examples/feature-deprecation-detector.sh +109 -0
- package/examples/file-change-tracker.sh +1 -1
- package/examples/file-change-undo-tracker.sh +0 -0
- package/examples/file-edit-backup.sh +63 -14
- package/examples/file-reference-check.sh +0 -0
- package/examples/file-size-limit.sh +12 -0
- package/examples/financial-operation-guard.sh +12 -0
- package/examples/firewall-guard.sh +12 -0
- package/examples/fish-shell-wrapper.sh +125 -7
- package/examples/five-hundred-milestone.sh +1 -0
- package/examples/flask-static-route-guard.sh +89 -0
- package/examples/forbidden-response-phrase-detector.sh +161 -0
- package/examples/gem-push-guard.sh +13 -0
- package/examples/gh-cli-destructive-guard.sh +13 -1
- package/examples/git-checkout-safety-guard.sh +12 -0
- package/examples/git-checkout-uncommitted-guard.sh +12 -0
- package/examples/git-config-guard.sh +12 -0
- package/examples/git-crypt-worktree-guard.sh +12 -0
- package/examples/git-filter-repo-guard.sh +56 -0
- package/examples/git-history-rewrite-guard.sh +12 -0
- package/examples/git-hook-bypass-guard.sh +0 -0
- package/examples/git-maintenance-guard.sh +83 -0
- package/examples/git-merge-conflict-prevent.sh +0 -0
- package/examples/git-message-length-check.sh +0 -0
- package/examples/git-message-length.sh +0 -0
- package/examples/git-operations-require-approval.sh +68 -14
- package/examples/git-pack-temp-cleanup-guard.sh +102 -0
- package/examples/git-push-blast-radius-guard.sh +218 -0
- package/examples/git-remote-guard.sh +24 -3
- package/examples/git-rm-orphan-wipe-guard.sh +85 -0
- package/examples/git-stash-before-checkout.sh +12 -0
- package/examples/git-stash-before-danger.sh +0 -0
- package/examples/git-submodule-guard.sh +69 -2
- package/examples/git-tag-guard.sh +12 -0
- package/examples/github-actions-secret-guard.sh +0 -0
- package/examples/gitignore-check.sh +0 -0
- package/examples/gitops-drift-guard.sh +12 -0
- package/examples/go-mod-tidy-warn.sh +1 -0
- package/examples/go-vet-after-edit.sh +12 -0
- package/examples/goal-iteration-limit-warner.sh +152 -0
- package/examples/grep-nul-false-negative-guard.sh +30 -0
- package/examples/growthbook-flag-monitor.sh +257 -0
- package/examples/hallucination-url-check.sh +1 -1
- package/examples/halt-signal-detector.sh +135 -0
- package/examples/handoff-on-clear.sh +65 -0
- package/examples/hardcoded-ip-guard.sh +1 -0
- package/examples/headless-empty-result-guard.sh +0 -0
- package/examples/headless-stop-guard.sh +0 -0
- package/examples/helm-install-guard.sh +2 -1
- package/examples/home-critical-bash-guard.sh +17 -1
- package/examples/hook-debug-wrapper.sh +6 -2
- package/examples/hook-permission-fixer.sh +0 -0
- package/examples/hook-self-disable-detector.sh +99 -0
- package/examples/hook-stdout-sanitizer.sh +6 -2
- package/examples/hook-tamper-guard.sh +12 -0
- package/examples/idle-session-cost-alert.sh +0 -0
- package/examples/image-dimension-guard.sh +109 -0
- package/examples/image-file-validator.sh +0 -0
- package/examples/iteration-quality-degradation-detector.sh +170 -0
- package/examples/java-compile-on-edit.sh +1 -1
- package/examples/json-syntax-check.sh +0 -0
- package/examples/k8s-production-guard.sh +13 -1
- package/examples/kill-process-guard.sh +12 -0
- package/examples/kubernetes-guard.sh +13 -1
- package/examples/laravel-artisan-guard.sh +13 -0
- package/examples/large-file-guard.sh +1 -1
- package/examples/log-level-guard.sh +0 -0
- package/examples/log-truncation-guard.sh +12 -0
- package/examples/long-session-malformed-tool-call-detector.sh +183 -0
- package/examples/loop-detector.sh +12 -0
- package/examples/magic-number-warn.sh +1 -0
- package/examples/main-branch-warn.sh +12 -0
- package/examples/markdown-link-check.sh +0 -0
- package/examples/max-concurrent-agents.sh +12 -0
- package/examples/max-edit-size-guard.sh +13 -0
- package/examples/max-file-count-guard.sh +0 -0
- package/examples/max-file-delete-count.sh +0 -0
- package/examples/max-function-length.sh +1 -0
- package/examples/max-import-count.sh +0 -0
- package/examples/max-subagent-count.sh +0 -0
- package/examples/mcp-config-freeze.sh +12 -0
- package/examples/mcp-config-poisoning-audit.sh +150 -0
- package/examples/mcp-data-boundary.sh +1 -1
- package/examples/mcp-misdiagnosis-arrest.sh +209 -0
- package/examples/mcp-orphan-leak-warner.sh +49 -0
- package/examples/mcp-permissions-ask-warner.sh +151 -0
- package/examples/mcp-routine-approval-detector.sh +154 -0
- package/examples/mcp-server-allowlist.sh +12 -0
- package/examples/mcp-server-guard.sh +12 -0
- package/examples/mcp-startup-bloat-detector.sh +87 -0
- package/examples/mcp-stdio-compatibility-test.sh +153 -0
- package/examples/mcp-tool-audit-log.sh +0 -0
- package/examples/mcp-tool-guard.sh +101 -1
- package/examples/mcp-warmup-wait.sh +0 -0
- package/examples/memory-chain-audit.sh +56 -0
- package/examples/memory-orphan-detector.sh +188 -0
- package/examples/memory-write-guard.sh +99 -17
- package/examples/migration-verify-guard.sh +12 -0
- package/examples/model-swap-suggester.sh +177 -0
- package/examples/model-version-alert.sh +5 -1
- package/examples/model-version-lock.sh +63 -0
- package/examples/move-delete-sequence-guard.sh +33 -2
- package/examples/multi-file-plan-routing-gate.sh +192 -0
- package/examples/multi-vendor-concurrent-warner.sh +108 -0
- package/examples/multi-window-auth-drift-detector.sh +183 -0
- package/examples/multiline-command-approver.sh +161 -23
- package/examples/nested-background-agent-guard.sh +109 -0
- package/examples/nested-spawn-inflight-guard.sh +178 -0
- package/examples/network-exfil-guard.sh +12 -0
- package/examples/network-guard.sh +12 -0
- package/examples/network-interface-guard.sh +12 -0
- package/examples/nextjs-env-guard.sh +1 -1
- package/examples/no-absolute-import.sh +0 -0
- package/examples/no-alert-confirm-prompt.sh +0 -0
- package/examples/no-anonymous-default-export.sh +0 -0
- package/examples/no-any-type.sh +0 -0
- package/examples/no-any-typescript.sh +1 -0
- package/examples/no-ask-human.sh +12 -0
- package/examples/no-assignment-in-condition.sh +0 -0
- package/examples/no-base64-exfil.sh +12 -0
- package/examples/no-callback-hell.sh +0 -0
- package/examples/no-circular-dependency.sh +0 -0
- package/examples/no-cleartext-storage.sh +0 -0
- package/examples/no-commented-code.sh +0 -0
- package/examples/no-commit-fixup.sh +0 -0
- package/examples/no-console-assert.sh +0 -0
- package/examples/no-console-error-swallow.sh +0 -0
- package/examples/no-console-in-prod.sh +0 -0
- package/examples/no-console-log-commit.sh +12 -0
- package/examples/no-console-log.sh +0 -0
- package/examples/no-console-time.sh +0 -0
- package/examples/no-cors-wildcard.sh +4 -1
- package/examples/no-curl-upload.sh +0 -0
- package/examples/no-dangerouslySetInnerHTML.sh +0 -0
- package/examples/no-dangling-await.sh +1 -0
- package/examples/no-debug-commit.sh +12 -0
- package/examples/no-debug-in-commit.sh +0 -0
- package/examples/no-deep-nesting.sh +0 -0
- package/examples/no-deep-relative-import.sh +1 -0
- package/examples/no-default-credentials.sh +0 -0
- package/examples/no-deploy-friday.sh +13 -1
- package/examples/no-disabled-test.sh +0 -0
- package/examples/no-document-write.sh +0 -0
- package/examples/no-empty-function.sh +0 -0
- package/examples/no-eval-in-template.sh +0 -0
- package/examples/no-eval-template.sh +3 -1
- package/examples/no-eval.sh +0 -0
- package/examples/no-exec-user-input.sh +0 -0
- package/examples/no-fixme-ship.sh +12 -0
- package/examples/no-floating-promises.sh +0 -0
- package/examples/no-force-flag.sh +22 -5
- package/examples/no-force-install.sh +0 -0
- package/examples/no-git-amend.sh +12 -0
- package/examples/no-git-rebase-public.sh +0 -0
- package/examples/no-global-install.sh +12 -0
- package/examples/no-global-state.sh +0 -0
- package/examples/no-hardcoded-port.sh +1 -0
- package/examples/no-hardcoded-url.sh +0 -0
- package/examples/no-helmet-missing.sh +0 -0
- package/examples/no-http-url.sh +1 -0
- package/examples/no-http-without-https.sh +0 -0
- package/examples/no-inline-style.sh +0 -0
- package/examples/no-inline-styles.sh +1 -0
- package/examples/no-innerhtml.sh +0 -0
- package/examples/no-install-global.sh +12 -0
- package/examples/no-jwt-in-url.sh +0 -0
- package/examples/no-large-commit.sh +0 -0
- package/examples/no-localhost-expose.sh +0 -0
- package/examples/no-magic-number.sh +0 -0
- package/examples/no-md5-sha1.sh +0 -0
- package/examples/no-mixed-line-endings.sh +8 -1
- package/examples/no-mutation-in-reducer.sh +0 -0
- package/examples/no-nested-ternary.sh +0 -0
- package/examples/no-network-exfil.sh +0 -0
- package/examples/no-open-redirect.sh +0 -0
- package/examples/no-output-truncation.sh +12 -0
- package/examples/no-package-downgrade.sh +0 -0
- package/examples/no-package-lock-edit.sh +12 -0
- package/examples/no-path-join-user-input.sh +0 -0
- package/examples/no-port-bind.sh +0 -0
- package/examples/no-process-exit.sh +0 -0
- package/examples/no-prototype-pollution.sh +0 -0
- package/examples/no-push-without-ci.sh +0 -0
- package/examples/no-push-without-tests.sh +12 -0
- package/examples/no-raw-password-in-url.sh +0 -0
- package/examples/no-root-user-docker.sh +1 -0
- package/examples/no-root-write.sh +12 -0
- package/examples/no-secrets-in-args.sh +4 -1
- package/examples/no-secrets-in-logs.sh +0 -0
- package/examples/no-sensitive-log.sh +0 -0
- package/examples/no-sleep-in-hooks.sh +0 -0
- package/examples/no-star-import-python.sh +1 -0
- package/examples/no-string-concat-sql.sh +0 -0
- package/examples/no-sudo-guard.sh +12 -0
- package/examples/no-sync-fs.sh +0 -0
- package/examples/no-todo-in-merge.sh +0 -0
- package/examples/no-todo-in-production.sh +1 -0
- package/examples/no-todo-without-issue.sh +0 -0
- package/examples/no-unused-import.sh +0 -0
- package/examples/no-var-keyword.sh +0 -0
- package/examples/no-verify-blocker.sh +12 -0
- package/examples/no-wget-piped-bash.sh +12 -0
- package/examples/no-wildcard-cors.sh +0 -0
- package/examples/no-wildcard-delete.sh +0 -0
- package/examples/no-wildcard-import.sh +0 -0
- package/examples/no-with-statement.sh +0 -0
- package/examples/no-write-outside-src.sh +0 -0
- package/examples/no-xml-external-entity.sh +0 -0
- package/examples/non-english-quality-warner.sh +156 -0
- package/examples/notify-waiting.sh +1 -1
- package/examples/npm-audit-warn.sh +0 -0
- package/examples/npm-global-install-guard.sh +12 -0
- package/examples/npm-publish-guard.sh +12 -0
- package/examples/npm-script-injection.sh +0 -0
- package/examples/npm-supply-chain-guard.sh +0 -0
- package/examples/nuxt-config-guard.sh +1 -0
- package/examples/oauth-refresh-monitor.sh +210 -0
- package/examples/opus-degradation-tracker.sh +187 -0
- package/examples/opus48-routine-task-warning.sh +196 -0
- package/examples/opus48-thinking-wedge-advisor.sh +143 -0
- package/examples/output-credential-scan.sh +1 -1
- package/examples/output-secret-mask.sh +31 -9
- package/examples/output-token-spike-detector.sh +145 -0
- package/examples/package-json-guard.sh +12 -0
- package/examples/package-lock-frozen.sh +12 -0
- package/examples/parallel-batch-size-limiter.sh +121 -0
- package/examples/parallel-cascade-detector.sh +116 -0
- package/examples/partial-view-claim-arrest.sh +174 -0
- package/examples/path-deny-bash-guard.sh +12 -0
- package/examples/path-traversal-guard.sh +12 -0
- package/examples/per-prompt-token-cap.sh +124 -0
- package/examples/permission-audit-log.sh +1 -1
- package/examples/permission-denial-enforcer.sh +12 -0
- package/examples/permission-entry-validator.sh +0 -0
- package/examples/persisted-1m-model-advisor.sh +88 -0
- package/examples/php-lint-on-edit.sh +1 -1
- package/examples/pii-upload-guard.sh +12 -0
- package/examples/pip-publish-guard.sh +13 -0
- package/examples/pip-requirements-guard.sh +12 -0
- package/examples/pip-venv-required.sh +12 -0
- package/examples/plan-mode-edit-guard.sh +12 -0
- package/examples/plan-mode-enforcer.sh +12 -0
- package/examples/plan-mode-strict-guard.sh +12 -0
- package/examples/plugin-hooks-json-bloat-detector.sh +169 -0
- package/examples/plugin-process-cleanup.sh +0 -0
- package/examples/polyglot-rm-guard.sh +12 -0
- package/examples/post-compact-safety.sh +12 -0
- package/examples/post-edit-disk-verify.sh +152 -0
- package/examples/powershell-remove-item-guard.sh +85 -0
- package/examples/pr-description-check.sh +0 -0
- package/examples/pr-duplicate-guard.sh +13 -0
- package/examples/pre-bash-sed-line-ending-windows.sh +87 -0
- package/examples/pre-compact-knowledge-save.sh +0 -0
- package/examples/pre-compact-transcript-backup.sh +0 -0
- package/examples/pre-execution-claim-detector.sh +179 -0
- package/examples/prefer-builtin-tools.sh +10 -1
- package/examples/prefer-const.sh +0 -0
- package/examples/prefer-dedicated-tools.sh +12 -0
- package/examples/prefer-optional-chaining.sh +0 -0
- package/examples/prisma-migrate-guard.sh +24 -7
- package/examples/production-port-kill-guard.sh +12 -0
- package/examples/prompt-injection-guard.sh +2 -1
- package/examples/prompt-usage-logger.sh +0 -0
- package/examples/protect-claudemd.sh +12 -0
- package/examples/protect-dotfiles.sh +12 -0
- package/examples/proxy-capture-suggester.sh +159 -0
- package/examples/public-artefact-socratic-narrowing.sh +232 -0
- package/examples/public-repo-push-guard.sh +12 -0
- package/examples/push-requires-test-pass-record.sh +0 -0
- package/examples/push-requires-test-pass.sh +12 -0
- package/examples/quota-anomaly-detector.sh +173 -0
- package/examples/quota-reset-audit.sh +58 -0
- package/examples/quoted-flag-approver.sh +99 -10
- package/examples/rails-migration-guard.sh +12 -0
- package/examples/rate-limit-guard.sh +0 -0
- package/examples/read-all-files-enforcer.sh +0 -0
- package/examples/read-budget-guard.sh +12 -0
- package/examples/read-loop-detector.sh +59 -0
- package/examples/read-once-guard.sh +96 -0
- package/examples/read-only-mode.sh +12 -0
- package/examples/readme-exists-check.sh +0 -0
- package/examples/record-read-coverage.sh +73 -0
- package/examples/redirect-fragment-warner.sh +149 -0
- package/examples/redis-flushall-guard.sh +13 -0
- package/examples/redundant-read-blocker.sh +132 -0
- package/examples/refusal-arrest-gate.sh +248 -0
- package/examples/registry-publish-guard.sh +13 -1
- package/examples/remote-control-billing-classifier.sh +135 -0
- package/examples/replace-all-guard.sh +12 -0
- package/examples/repo-visibility-guard.sh +12 -0
- package/examples/reroute-after-block-guard.sh +150 -0
- package/examples/response-budget-guard.sh +0 -0
- package/examples/resume-drift-watcher.sh +57 -0
- package/examples/rg-replace-flag-detector.sh +125 -0
- package/examples/rhetorical-verification-prompt-detector.sh +102 -0
- package/examples/ripgrep-permission-fix.sh +0 -0
- package/examples/rm-safety-net.sh +151 -8
- package/examples/role-tool-guard.sh +12 -0
- package/examples/route-handler-emptiness-gate.sh +324 -0
- package/examples/ruby-lint-on-edit.sh +1 -1
- package/examples/runtime-binary-change-detector.sh +102 -0
- package/examples/same-command-repeat-detector.sh +196 -0
- package/examples/same-correction-arrest.sh +169 -0
- package/examples/sandbox-denywrite-enforcer.sh +78 -0
- package/examples/sandbox-relative-path-audit.sh +83 -25
- package/examples/sandbox-write-verify.sh +12 -0
- package/examples/schema-migration-guard.sh +0 -0
- package/examples/scope-expansion-receipt.sh +178 -0
- package/examples/scope-guard.sh +88 -9
- package/examples/secret-file-read-guard.sh +12 -0
- package/examples/secret-file-write-guard.sh +150 -0
- package/examples/self-modify-bypass-guard.sh +0 -0
- package/examples/sensitive-file-read-guard.sh +23 -3
- package/examples/sensitive-log-guard.sh +1 -0
- package/examples/server-side-prompt-injection-detector.sh +69 -0
- package/examples/session-agent-cost-limiter.sh +12 -0
- package/examples/session-backup-on-start.sh +1 -1
- package/examples/session-cost-alert.sh +12 -0
- package/examples/session-drift-guard.sh +12 -0
- package/examples/session-duration-guard.sh +25 -2
- package/examples/session-end-logger.sh +0 -0
- package/examples/session-health-monitor.sh +0 -0
- package/examples/session-index-repair.sh +1 -1
- package/examples/session-memory-watchdog.sh +1 -0
- package/examples/session-permission-reset-guard.sh +12 -0
- package/examples/session-persistence-verifier.sh +93 -0
- package/examples/session-plugin-pin-watch.sh +68 -0
- package/examples/session-rate-monitor.sh +176 -0
- package/examples/session-resume-env-fix.sh +0 -0
- package/examples/session-start-quota-status.sh +193 -0
- package/examples/session-start-safety-check.sh +55 -3
- package/examples/session-state-saver.sh +0 -0
- package/examples/session-summary-stop.sh +1 -1
- package/examples/session-summary.sh +0 -0
- package/examples/session-token-counter.sh +1 -1
- package/examples/settings-hooks-key-restorer.sh +99 -0
- package/examples/settings-json-health-check.sh +57 -0
- package/examples/settings-json-model-guard.sh +0 -0
- package/examples/settings-regression-tester.sh +188 -0
- package/examples/shell-config-truncation-guard.sh +12 -0
- package/examples/shell-wrapper-guard.sh +12 -0
- package/examples/skill-cumulative-size-detector.sh +104 -0
- package/examples/skill-description-drop-detector.sh +148 -0
- package/examples/skill-gate.sh +0 -0
- package/examples/skill-truncation-detector.sh +154 -0
- package/examples/skills-context-recorder.sh +167 -0
- package/examples/skills-load-verifier.sh +96 -0
- package/examples/skills-settings-validator.sh +139 -0
- package/examples/sonnet-45-deprecation-helper.sh +85 -0
- package/examples/spec-file-scope-guard.sh +12 -0
- package/examples/spring-profile-guard.sh +1 -0
- package/examples/spurious-malformed-notice-detector.sh +247 -0
- package/examples/sql-bulk-delete-warn.sh +88 -0
- package/examples/sql-injection-detect.sh +0 -0
- package/examples/ssh-key-protect.sh +12 -0
- package/examples/staged-secret-scan.sh +22 -1
- package/examples/stale-temp-settings-detector.sh +86 -0
- package/examples/standing-rule-session-surfacer.sh +137 -0
- package/examples/stop-hook-sigterm-wrapper.sh +182 -0
- package/examples/stop-transcript-write-health.sh +64 -0
- package/examples/strict-allowlist.sh +57 -15
- package/examples/strip-coauthored-by.sh +50 -10
- package/examples/subagent-blast-radius-guard.sh +184 -0
- package/examples/subagent-boundary-precheck.sh +126 -0
- package/examples/subagent-budget-guard.sh +12 -0
- package/examples/subagent-claudemd-inject.sh +0 -0
- package/examples/subagent-closure-verify-gate.sh +164 -0
- package/examples/subagent-destructive-git-guard.sh +120 -0
- package/examples/subagent-error-detector.sh +0 -0
- package/examples/subagent-forged-system-reminder-guard.sh +156 -0
- package/examples/subagent-identity-leak-guard.sh +102 -0
- package/examples/subagent-identity-reassertion.sh +51 -0
- package/examples/subagent-inheritance-tester.sh +179 -0
- package/examples/subagent-permission-mode-guard.sh +110 -0
- package/examples/subagent-scope-guard.sh +12 -0
- package/examples/subagent-spawn-verification-enforcer.sh +102 -0
- package/examples/subagent-tool-allowlist-enforcer.sh +101 -0
- package/examples/subagent-tool-call-limiter.sh +87 -15
- package/examples/subcommand-chain-guard.sh +12 -0
- package/examples/subscription-api-billing-warner.sh +160 -0
- package/examples/subscription-bypass-detector.sh +152 -0
- package/examples/svelte-lint-on-edit.sh +1 -0
- package/examples/swift-build-on-edit.sh +1 -1
- package/examples/symlink-guard.sh +27 -2
- package/examples/symlink-protect.sh +1 -0
- package/examples/system-dir-protection-guard.sh +73 -8
- package/examples/system-message-workaround.sh +38 -13
- package/examples/system-package-guard.sh +12 -0
- package/examples/systemd-service-guard.sh +12 -0
- package/examples/task-integrity-guard.sh +12 -0
- package/examples/temp-file-cleanup.sh +1 -1
- package/examples/temporal-suggestion-detector.sh +135 -0
- package/examples/terraform-guard.sh +27 -6
- package/examples/test-after-edit.sh +1 -1
- package/examples/test-before-push.sh +12 -0
- package/examples/test-coverage-reminder.sh +24 -1
- package/examples/thinking-budget-effort-mismatch-detector.sh +149 -0
- package/examples/thinking-stall-detector.sh +61 -0
- package/examples/timezone-guard.sh +0 -0
- package/examples/tmp-output-size-guard.sh +0 -0
- package/examples/todo-check.sh +1 -1
- package/examples/token-budget-guard.sh +12 -0
- package/examples/token-budget-per-task.sh +12 -0
- package/examples/token-usage-tracker.sh +7 -1
- package/examples/tokenizer-ratio-alert-corpus.sh +90 -0
- package/examples/tokenizer-ratio-alert.sh +104 -0
- package/examples/tool-call-rate-limiter.sh +0 -0
- package/examples/tool-result-correlation-checker.sh +167 -0
- package/examples/tool-result-size-guard.sh +132 -0
- package/examples/tool-retry-budget-guard.sh +12 -0
- package/examples/transcript-contamination-detector.sh +138 -0
- package/examples/trustfall-mcp-injection-guard.sh +103 -0
- package/examples/ultrareview-large-diff-advisor.sh +184 -0
- package/examples/unbounded-output-guard.sh +94 -0
- package/examples/uncommitted-changes-stop.sh +1 -0
- package/examples/uncommitted-discard-guard.sh +23 -5
- package/examples/uncommitted-work-guard.sh +12 -0
- package/examples/usage-warn.sh +0 -0
- package/examples/user-account-guard.sh +12 -0
- package/examples/userprompt-submit-receipt.sh +123 -0
- package/examples/variable-expansion-guard.sh +12 -0
- package/examples/verify-after-publish-reminder.sh +93 -0
- package/examples/verify-before-commit.sh +12 -0
- package/examples/version-bump-detector.sh +156 -0
- package/examples/version-regression-warner.sh +144 -0
- package/examples/vue-lint-on-edit.sh +1 -0
- package/examples/warn-cron-cost-trap.sh +173 -0
- package/examples/webfetch-runaway-guard.sh +89 -0
- package/examples/wellness-break-reminder.sh +118 -0
- package/examples/windows-destructive-command-guard.sh +177 -0
- package/examples/windows-path-guard.sh +12 -0
- package/examples/windows-python-stub-detector.sh +63 -0
- package/examples/work-hours-guard.sh +12 -0
- package/examples/working-directory-fence.sh +12 -0
- package/examples/workspace-lease-guard.sh +205 -0
- package/examples/worktree-create-log.sh +1 -0
- package/examples/worktree-delete-guard.sh +12 -0
- package/examples/worktree-edit-boundary-guard.sh +127 -0
- package/examples/worktree-escape-write-guard.sh +114 -0
- package/examples/worktree-hook-linker.sh +0 -0
- package/examples/worktree-hooks-path-fix.sh +111 -0
- package/examples/worktree-parent-write-guard.sh +43 -0
- package/examples/worktree-project-unify.sh +2 -1
- package/examples/worktree-remove-uncommitted-guard.sh +13 -0
- package/examples/worktree-unmerged-guard.sh +7 -1
- package/examples/write-byte-integrity-verifier.sh +190 -0
- package/examples/write-empty-content-guard.sh +67 -0
- package/examples/write-nul-corruption-detector.sh +61 -0
- package/examples/write-overwrite-confirm.sh +160 -14
- package/examples/write-secret-guard.sh +27 -5
- package/examples/write-shrink-guard.sh +12 -0
- package/examples/write-test-ratio.sh +0 -0
- package/examples/wsl-host-disk-space-guard.sh +97 -0
- package/examples/xml-format-leak-detector.sh +266 -0
- package/examples/yaml-syntax-check.sh +12 -0
- package/hooks/hooks.json +6 -6
- package/index.mjs +1699 -183
- package/mission.md +2 -0
- package/package.json +4 -4
- package/plugins/credential-guard/.claude-plugin/plugin.json +9 -7
- package/plugins/git-protection/.claude-plugin/plugin.json +10 -8
- package/plugins/safety-essentials/.claude-plugin/plugin.json +9 -7
- package/plugins/token-guard/.claude-plugin/plugin.json +10 -8
- package/scripts/agents-md-sync-setup.sh +156 -0
- package/scripts/autonomy-blocked-summary.sh +148 -0
- package/scripts/build-search-index.py +43 -0
- package/scripts/build-sitemap.py +119 -0
- package/scripts/cc-doctor.sh +192 -0
- package/scripts/check-hook-event-names.py +127 -0
- package/scripts/check-misfire-instrument.sh +64 -0
- package/scripts/claim-verify-audit.sh +467 -0
- package/scripts/cowork-claudemd-helper.sh +136 -0
- package/scripts/june-15-deprecated-model-scan.sh +111 -0
- package/scripts/measure-heredoc-shapes.sh +67 -0
- package/scripts/measure-literal-match-misfire.sh +110 -0
- package/scripts/probe-scope-guard-branches.sh +48 -0
- package/scripts/probe-skip-line-both-ways.sh +65 -0
- package/scripts/receipts-aggregate.py +199 -0
- package/scripts/session-forensic-audit.py +360 -0
- package/scripts.json +9 -9
- package/scripts.json.bak-2026-07-27-find +13 -0
- package/skills/safety-setup/SKILL.md +5 -5
- package/tests/approve-side-remaining-two.test.sh +129 -0
- package/tests/approver-list-granularity.test.sh +145 -0
- package/tests/askuserquestion-autonomy-gate.test.sh +181 -0
- package/tests/audit-ci-gate.test.sh +87 -0
- package/tests/audit-cross-layer-claudemd.test.sh +170 -0
- package/tests/audit-fail-open-parse.test.sh +100 -0
- package/tests/auto-approve-compound-tail.test.sh +194 -0
- package/tests/auto-mode-path-invoked-commands.test.sh +89 -0
- package/tests/auto-mode-quoted-targets.test.sh +127 -0
- package/tests/auto-mode-unquoted-targets.test.sh +112 -0
- package/tests/bash-secret-output-detector-detects.test.sh +102 -0
- package/tests/blindspots-cross-layer.test.sh +177 -0
- package/tests/block-database-wipe.test.sh +64 -0
- package/tests/bundled-short-flags-bypass.test.sh +85 -0
- package/tests/cd-git-allow-compound-tail.test.sh +67 -0
- package/tests/chown-guard-filesystem-root.test.sh +64 -0
- package/tests/ci-workflow-guard-skip-rule.test.sh +115 -0
- package/tests/compound-deny-safe-rm-targets.test.sh +105 -0
- package/tests/core-scripts-parser-fallback.test.sh +140 -0
- package/tests/destructive-guard-bare-glob.test.sh +74 -0
- package/tests/destructive-guard-every-operand.test.sh +100 -0
- package/tests/destructive-guard-find-deletion.test.sh +114 -0
- package/tests/destructive-guard-flag-order.test.sh +106 -0
- package/tests/destructive-guard-mentions-vs-invocations.test.sh +107 -0
- package/tests/destructive-guard-quoted-target.test.sh +89 -0
- package/tests/destructive-guard-separators.test.sh +105 -0
- package/tests/destructive-guard-variable-target.test.sh +98 -0
- package/tests/destructive-guard-wrapped-command.test.sh +91 -0
- package/tests/doctor-hook-disabling-env.test.sh +92 -0
- package/tests/doctor-misspelled-settings-keys.test.sh +106 -0
- package/tests/example-guards-wrapped-command.test.sh +169 -0
- package/tests/file-edit-backup.test.sh +93 -0
- package/tests/git-filter-repo-guard.test.sh +60 -0
- package/tests/git-global-options-bypass.test.sh +141 -0
- package/tests/git-invocation-prefixes-all-guards.test.sh +114 -0
- package/tests/git-maintenance-guard.test.sh +83 -0
- package/tests/git-pack-temp-cleanup-guard.test.sh +133 -0
- package/tests/git-rm-orphan-wipe-guard.test.sh +66 -0
- package/tests/git-submodule-guard.test.sh +50 -0
- package/tests/grep-pcre-portability.test.sh +155 -0
- package/tests/hook-registration-matches-input.test.sh +73 -0
- package/tests/hook-trigger-matches-envelope.test.sh +178 -0
- package/tests/install-does-not-claim-protection.test.sh +110 -0
- package/tests/install-example-standalone-tools.test.sh +139 -0
- package/tests/line-continuation-bypass.test.sh +114 -0
- package/tests/mcp-config-poisoning-audit.test.sh +106 -0
- package/tests/nested-background-agent-guard.test.sh +58 -0
- package/tests/no-unqualified-safety-claims.test.sh +114 -0
- package/tests/option-eating-grep-patterns.test.sh +130 -0
- package/tests/outdated-core-guards.test.sh +134 -0
- package/tests/outdated-report.test.sh +155 -0
- package/tests/output-secret-mask-warns.test.sh +73 -0
- package/tests/plugin-hooks-fail-open-under-sh.test.sh +165 -0
- package/tests/plugins-word-order.test.sh +126 -0
- package/tests/powershell-remove-item-guard.test.sh +85 -0
- package/tests/project-dir-naming.test.sh +103 -0
- package/tests/quoted-safe-targets-and-mentions.test.sh +190 -0
- package/tests/reroute-after-block-guard.test.sh +104 -0
- package/tests/secret-guard-documented-promises.test.sh +97 -0
- package/tests/session-plugin-pin-watch.test.sh +45 -0
- package/tests/settings-unreadable-refuses-to-write.test.sh +95 -0
- package/tests/shield-no-silent-adoption.test.py +110 -0
- package/tests/shield-no-silent-adoption.test.sh +46 -0
- package/tests/stop-transcript-write-health.test.sh +46 -0
- package/tests/system-dir-guard-root-erased.test.sh +66 -0
- package/tests/test-account-billing-log.sh +100 -0
- package/tests/test-account-routing-preflight.sh +77 -0
- package/tests/test-agent-sdk-credit-pool-monitor.sh +157 -0
- package/tests/test-agent-view-quota-warn.sh +184 -0
- package/tests/test-agents-md-edit-drift-warner.sh +176 -0
- package/tests/test-agents-md-loader.sh +204 -0
- package/tests/test-agents-md-sync-checker.sh +125 -0
- package/tests/test-ai-slop-punctuation-arrest.sh +280 -0
- package/tests/test-allowlist.sh +60 -0
- package/tests/test-always-allow-pattern-suggester.sh +147 -0
- package/tests/test-anthropic-base-url-guard.sh +88 -0
- package/tests/test-articulated-scope-capture.sh +139 -0
- package/tests/test-attachment-traversal-guard.sh +168 -0
- package/tests/test-aup-block-pattern-logger.sh +315 -0
- package/tests/test-aup-false-positive-helper.sh +188 -0
- package/tests/test-aup-large-tool-output-warner.sh +370 -0
- package/tests/test-aup-retry-loop-guard.sh +341 -0
- package/tests/test-auth-expiry-reminder.sh +303 -0
- package/tests/test-auth-macos-sleep-detector.sh +254 -0
- package/tests/test-auth-path-detector.sh +232 -0
- package/tests/test-auth-status-checker.sh +233 -0
- package/tests/test-authorized-reconfirmation-detector.sh +280 -0
- package/tests/test-background-cost-launch-guard.sh +62 -0
- package/tests/test-bash-allowlist-secondary-check.sh +143 -0
- package/tests/test-bash-fanout-bounded-rewriter.sh +186 -0
- package/tests/test-bash-project-fence.sh +127 -0
- package/tests/test-bg-permission-prompt-warner.sh +221 -0
- package/tests/test-binary-read-detector.sh +173 -0
- package/tests/test-broad-prefix-session-trap-warner.sh +167 -0
- package/tests/test-bulk-delete-target-resolution.sh +49 -0
- package/tests/test-bypass-mode-effective-verifier.sh +179 -0
- package/tests/test-cache-creation-drift-detector.sh +244 -0
- package/tests/test-cache-residue-detector.sh +429 -0
- package/tests/test-cache-tier-logger.sh +59 -0
- package/tests/test-cache-ttl-eviction-detector.sh +282 -0
- package/tests/test-cch-sentinel-precommit-guard.sh +64 -0
- package/tests/test-claim-verify-detector.sh +222 -0
- package/tests/test-claim-vs-caveat-checker.sh +134 -0
- package/tests/test-claude-code-version-pin-advisor.sh +353 -0
- package/tests/test-claude-md-reinjector.sh +173 -0
- package/tests/test-claude-md-size-monitor.sh +107 -0
- package/tests/test-claude-update-budget-guard.sh +132 -0
- package/tests/test-claude-update-smart.sh +91 -0
- package/tests/test-claudemd-tool-prohibition.sh +239 -0
- package/tests/test-cli-config-pinning-detector.sh +233 -0
- package/tests/test-cliff-countdown-advisor.sh +138 -0
- package/tests/test-closure-word-verify-gate.sh +158 -0
- package/tests/test-commit-all-scope-guard.sh +73 -0
- package/tests/test-commitment-carry-forward-arrest.sh +250 -0
- package/tests/test-compact-circuit-breaker.sh +134 -0
- package/tests/test-compact-dispatch-watchdog.sh +147 -0
- package/tests/test-completion-claim-without-verification-detector.sh +326 -0
- package/tests/test-compound-bash-permission-resolver.sh +264 -0
- package/tests/test-compound-command-deny-enforcer.sh +67 -0
- package/tests/test-context-length-budget.sh +68 -0
- package/tests/test-context-usage-drift-alert.sh +52 -22
- package/tests/test-cost-incident-self-audit.sh +94 -0
- package/tests/test-cowork-claude-md-load-checker.sh +257 -0
- package/tests/test-cowork-claudemd-helper.sh +141 -0
- package/tests/test-cowork-fuse-staleness-watcher.sh +287 -0
- package/tests/test-cowork-hook-absence-warner.sh +230 -0
- package/tests/test-cowork-model-picker-advisor.sh +317 -0
- package/tests/test-credential-exfil-guard.sh +62 -0
- package/tests/test-cron-create-receipt.sh +165 -0
- package/tests/test-cross-product-mcp-spawn-detector.sh +112 -0
- package/tests/test-daemon-zombie-worker-surfacer.sh +71 -0
- package/tests/test-daily-cost-guard.sh +131 -0
- package/tests/test-deny-rule-integrity-verifier.sh +288 -0
- package/tests/test-deployment-readback-gate.sh +92 -0
- package/tests/test-deployment-readback-gh-adapter.sh +163 -0
- package/tests/test-disabled-feature-toggle-advisor.sh +78 -0
- package/tests/test-dispatch-allowlist-preflight.sh +385 -0
- package/tests/test-dispatch-liveness-watchdog.sh +319 -0
- package/tests/test-dispatch-receipt.sh +314 -0
- package/tests/test-dotenv-anthropic-key-billing-guard.sh +160 -0
- package/tests/test-echo-probe-spam-detector.sh +143 -0
- package/tests/test-edit-quote-ambiguity-guard.sh +75 -0
- package/tests/test-ephemeral-container-detector.sh +251 -0
- package/tests/test-evidence-claim-gate.sh +291 -0
- package/tests/test-exploration-budget-guard.sh +164 -0
- package/tests/test-extended-thinking-loop-guard.sh +289 -0
- package/tests/test-extended-thinking-resume-warning.sh +240 -0
- package/tests/test-extended-thinking-tool-use-mismatch-detector.sh +236 -0
- package/tests/test-fabricated-command-detector.sh +296 -0
- package/tests/test-false-disk-full-guard.sh +36 -0
- package/tests/test-feature-deprecation-detector.sh +117 -0
- package/tests/test-forbidden-response-phrase-detector.sh +246 -0
- package/tests/test-git-operations-require-approval.sh +53 -0
- package/tests/test-git-push-blast-radius-guard.sh +115 -0
- package/tests/test-goal-iteration-limit-warner.sh +128 -0
- package/tests/test-growthbook-flag-monitor.sh +428 -0
- package/tests/test-halt-signal-detector.sh +120 -0
- package/tests/test-hook-self-disable-detector.sh +232 -0
- package/tests/test-iteration-quality-degradation-detector.sh +244 -0
- package/tests/test-long-session-malformed-tool-call-detector.sh +185 -0
- package/tests/test-marketplace-plugins.sh +193 -0
- package/tests/test-mcp-misdiagnosis-arrest.sh +235 -0
- package/tests/test-mcp-orphan-leak-warner.sh +71 -0
- package/tests/test-mcp-permissions-ask-warner.sh +207 -0
- package/tests/test-mcp-routine-approval-detector.sh +229 -0
- package/tests/test-mcp-startup-bloat-detector.sh +141 -0
- package/tests/test-mcp-stdio-compatibility-test.sh +112 -0
- package/tests/test-memory-chain-audit.sh +59 -0
- package/tests/test-memory-orphan-detector.sh +227 -0
- package/tests/test-model-swap-suggester.sh +368 -0
- package/tests/test-model-version-lock.sh +83 -0
- package/tests/test-multi-file-plan-routing-gate.sh +277 -0
- package/tests/test-multi-window-auth-drift-detector.sh +262 -0
- package/tests/test-nested-spawn-inflight-guard.sh +281 -0
- package/tests/test-no-force-flag.sh +49 -0
- package/tests/test-non-english-quality-warner.sh +229 -0
- package/tests/test-oauth-refresh-monitor.sh +311 -0
- package/tests/test-opus-degradation-tracker.sh +274 -0
- package/tests/test-opus48-routine-task-warning.sh +201 -0
- package/tests/test-opus48-thinking-wedge-advisor.sh +249 -0
- package/tests/test-output-token-spike-detector.sh +315 -0
- package/tests/test-parallel-batch-size-limiter.sh +228 -0
- package/tests/test-parallel-cascade-detector.sh +191 -0
- package/tests/test-partial-view-claim-arrest.sh +272 -0
- package/tests/test-per-prompt-token-cap.sh +136 -0
- package/tests/test-persisted-1m-model-advisor.sh +71 -0
- package/tests/test-plugin-hooks-json-bloat-detector.sh +267 -0
- package/tests/test-post-edit-disk-verify.sh +294 -0
- package/tests/test-pre-bash-sed-line-ending-windows.sh +108 -0
- package/tests/test-pre-execution-claim-detector.sh +366 -0
- package/tests/test-private-key-backup-and-git-credentials.sh +100 -0
- package/tests/test-proxy-capture-suggester.sh +214 -0
- package/tests/test-public-artefact-socratic-narrowing.sh +346 -0
- package/tests/test-quota-anomaly-detector.sh +321 -0
- package/tests/test-quota-reset-audit.sh +81 -0
- package/tests/test-read-loop-detector.sh +137 -0
- package/tests/test-read-once-guard.sh +85 -0
- package/tests/test-receipts-aggregate.sh +143 -0
- package/tests/test-redirect-fragment-warner.sh +130 -0
- package/tests/test-redundant-read-blocker.sh +155 -0
- package/tests/test-refusal-arrest-gate.sh +303 -0
- package/tests/test-remote-control-billing-classifier.sh +125 -0
- package/tests/test-resume-drift-watcher.sh +65 -0
- package/tests/test-rg-replace-flag-detector.sh +175 -0
- package/tests/test-rhetorical-verification-prompt-detector.sh +237 -0
- package/tests/test-rm-safety-net.sh +115 -0
- package/tests/test-route-handler-emptiness-gate.sh +300 -0
- package/tests/test-runtime-binary-change-detector.sh +196 -0
- package/tests/test-same-command-repeat-detector.sh +165 -0
- package/tests/test-same-correction-arrest.sh +165 -0
- package/tests/test-scope-expansion-receipt.sh +207 -0
- package/tests/test-server-side-prompt-injection-detector.sh +181 -0
- package/tests/test-session-persistence-verifier.sh +128 -0
- package/tests/test-session-rate-monitor.sh +284 -0
- package/tests/test-session-start-quota-status.sh +210 -0
- package/tests/test-session-start-safety-check.sh +138 -0
- package/tests/test-settings-hooks-key-restorer.sh +257 -0
- package/tests/test-settings-json-health-check.sh +70 -0
- package/tests/test-settings-regression-tester.sh +197 -0
- package/tests/test-skill-cumulative-size-detector.sh +198 -0
- package/tests/test-skill-description-drop-detector.sh +236 -0
- package/tests/test-skill-truncation-detector.sh +263 -0
- package/tests/test-skills-context-recorder.sh +329 -0
- package/tests/test-skills-load-verifier.sh +184 -0
- package/tests/test-skills-settings-validator.sh +242 -0
- package/tests/test-sonnet-45-deprecation-helper.sh +150 -0
- package/tests/test-spurious-malformed-notice-detector.sh +290 -0
- package/tests/test-sql-bulk-delete-warn.sh +123 -0
- package/tests/test-ssh-key-protect.sh +81 -0
- package/tests/test-stale-temp-settings-detector.sh +161 -0
- package/tests/test-standing-rule-session-surfacer.sh +215 -0
- package/tests/test-starter-hooks-manifest.sh +96 -0
- package/tests/test-stop-hook-sigterm-wrapper.sh +258 -0
- package/tests/test-strict-allowlist.sh +72 -0
- package/tests/test-subagent-boundary-precheck.sh +137 -0
- package/tests/test-subagent-closure-verify-gate.sh +193 -0
- package/tests/test-subagent-destructive-git-guard.sh +86 -0
- package/tests/test-subagent-identity-leak-guard.sh +62 -0
- package/tests/test-subagent-identity-reassertion.sh +61 -0
- package/tests/test-subagent-inheritance-tester.sh +319 -0
- package/tests/test-subagent-permission-mode-guard.sh +61 -0
- package/tests/test-subagent-spawn-verification-enforcer.sh +60 -0
- package/tests/test-subagent-tool-allowlist-enforcer.sh +62 -0
- package/tests/test-subagent-tool-call-limiter.sh +97 -0
- package/tests/test-subscription-api-billing-warner.sh +138 -0
- package/tests/test-subscription-bypass-detector.sh +255 -0
- package/tests/test-temporal-suggestion-detector.sh +183 -0
- package/tests/test-thinking-budget-effort-mismatch-detector.sh +327 -0
- package/tests/test-thinking-stall-detector.sh +151 -0
- package/tests/test-tokenizer-ratio-alert-corpus.sh +77 -0
- package/tests/test-tokenizer-ratio-alert.sh +93 -0
- package/tests/test-tool-result-correlation-checker.sh +264 -0
- package/tests/test-tool-result-size-guard.sh +121 -0
- package/tests/test-transcript-contamination-detector.sh +264 -0
- package/tests/test-trigger-header-parsing.sh +151 -0
- package/tests/test-ultrareview-large-diff-advisor.sh +192 -0
- package/tests/test-userprompt-submit-receipt.sh +181 -0
- package/tests/test-verify-after-publish-reminder.sh +184 -0
- package/tests/test-version-bump-detector.sh +212 -0
- package/tests/test-version-regression-warner.sh +165 -0
- package/tests/test-warn-cron-cost-trap.sh +82 -0
- package/tests/test-webfetch-runaway-guard.sh +77 -0
- package/tests/test-wellness-break-reminder.sh +138 -0
- package/tests/test-windows-destructive-command-guard.sh +169 -0
- package/tests/test-windows-python-stub-detector.sh +146 -0
- package/tests/test-worktree-edit-boundary-guard.sh +219 -0
- package/tests/test-write-byte-integrity-verifier.sh +192 -0
- package/tests/test-xml-format-leak-detector.sh +299 -0
- package/tests/trustfall-mcp-injection-guard.test.sh +183 -0
- package/tests/workspace-lease-guard.test.sh +144 -0
- package/tests/worktree-escape-write-guard.test.sh +68 -0
- package/tests/worktree-hooks-path-fix.test.sh +181 -0
- package/tests/worktree-parent-write-guard.test.sh +51 -0
- package/tests/write-empty-content-guard.test.sh +39 -0
- package/tests/write-nul-corruption-detector.test.sh +29 -0
- package/tests/write-overwrite-unread-content.test.sh +178 -0
- package/tests/wsl-host-disk-space-guard.test.sh +55 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# destructive-guard: mass deletion driven by find
|
|
3
|
+
#
|
|
4
|
+
# The old Check 5 matched only `find /`, `find ~` and `find ..` followed by
|
|
5
|
+
# -delete. The two forms people actually run -- `find . -delete` and
|
|
6
|
+
# `find . -exec rm -rf {} \;` -- walked straight past it, and so did every
|
|
7
|
+
# variant that quoted the flag or put a wrapper in front of the command.
|
|
8
|
+
# Two adversarial reviews in 2026-07 rejected earlier attempts because a
|
|
9
|
+
# simpler bypass always survived the word-boundary checks.
|
|
10
|
+
#
|
|
11
|
+
# The rewrite inverts the detection: normalise the line first (drop quotes,
|
|
12
|
+
# drop wrappers, resolve /usr/bin/find, join continuations), then ask three
|
|
13
|
+
# plain questions -- is the command find, does it delete, and how wide is the
|
|
14
|
+
# search. Everyday narrowed cleanup stays allowed; an unnarrowed sweep does not.
|
|
15
|
+
#
|
|
16
|
+
# Measured 2026-07-27: 26 of the 30 blocking cases below returned exit 0
|
|
17
|
+
# against the shipped guard.
|
|
18
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
19
|
+
GUARD=$(mktemp); trap 'rm -f "$GUARD"' EXIT
|
|
20
|
+
python3 -c "
|
|
21
|
+
import json,sys
|
|
22
|
+
sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$GUARD"
|
|
23
|
+
|
|
24
|
+
PASS=0; FAIL=0
|
|
25
|
+
|
|
26
|
+
check() {
|
|
27
|
+
local desc="$1" cmd="$2" want="$3" # want: 2 = blocked, 0 = allowed
|
|
28
|
+
local payload code
|
|
29
|
+
payload=$(python3 -c '
|
|
30
|
+
import json,sys
|
|
31
|
+
print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]}}))' "$cmd")
|
|
32
|
+
printf '%s' "$payload" | bash "$GUARD" >/dev/null 2>&1
|
|
33
|
+
code=$?
|
|
34
|
+
if [ "$code" = "$want" ]; then
|
|
35
|
+
echo "PASS: $desc"; PASS=$((PASS+1))
|
|
36
|
+
else
|
|
37
|
+
echo "FAIL: $desc (expected exit $want, got $code)"; FAIL=$((FAIL+1))
|
|
38
|
+
fi
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# --- the two forms people actually run ---------------------------------------
|
|
42
|
+
check "plain find -delete" 'find . -delete' 2
|
|
43
|
+
check "find -exec rm" 'find . -exec rm -rf {} \;' 2
|
|
44
|
+
check "find -execdir rm" 'find . -execdir rm -f {} \;' 2
|
|
45
|
+
check "find -exec unlink" 'find . -exec unlink {} \;' 2
|
|
46
|
+
check "no root given" 'find -delete' 2
|
|
47
|
+
|
|
48
|
+
# --- N series: quoting defeated the word boundaries --------------------------
|
|
49
|
+
check "quoted flag, single" "find . '-delete'" 2
|
|
50
|
+
check "quoted flag, double" 'find . "-delete"' 2
|
|
51
|
+
check "quoted rm inside -exec" "find . -exec 'rm' -rf {} \;" 2
|
|
52
|
+
|
|
53
|
+
# --- K series: a wrapper in front of the real command ------------------------
|
|
54
|
+
check "env wrapper" 'env find . -delete' 2
|
|
55
|
+
check "nice wrapper" 'nice find . -delete' 2
|
|
56
|
+
check "nice with option" 'nice -n 5 find . -delete' 2
|
|
57
|
+
check "timeout wrapper" 'timeout 30 find . -delete' 2
|
|
58
|
+
check "sudo wrapper" 'sudo find . -delete' 2
|
|
59
|
+
check "exec wrapper" 'exec find . -delete' 2
|
|
60
|
+
check "doubled command builtin" 'command command find . -delete' 2
|
|
61
|
+
check "relative path to find" './find . -delete' 2
|
|
62
|
+
check "absolute path to find" '/usr/bin/find . -delete' 2
|
|
63
|
+
check "leading assignment" 'FOO=1 find . -delete' 2
|
|
64
|
+
check "shell -c wrapper" 'bash -c "find . -delete"' 2
|
|
65
|
+
check "xargs in front" 'xargs find . -delete' 2
|
|
66
|
+
|
|
67
|
+
# --- dangerous search roots ---------------------------------------------------
|
|
68
|
+
check "root is /" "find / -name '*.log' -delete" 2
|
|
69
|
+
check "root is ~" "find ~ -name '*.tmp' -delete" 2
|
|
70
|
+
check "root is \$HOME" 'find $HOME -delete' 2
|
|
71
|
+
check "root is parent" 'find .. -delete' 2
|
|
72
|
+
|
|
73
|
+
# --- narrowing that does not actually narrow ---------------------------------
|
|
74
|
+
check "-type alone is not narrowing" 'find . -type f -delete' 2
|
|
75
|
+
check "bare wildcard is not narrowing" "find . -name '*' -delete" 2
|
|
76
|
+
check "-o rebinds the delete" "find . -name '*.pyc' -o -delete" 2
|
|
77
|
+
|
|
78
|
+
# --- reachable through any separator, and across a continued line ------------
|
|
79
|
+
check "bare & separator" 'true & find . -delete' 2
|
|
80
|
+
check "semicolon separator" 'true ; find . -delete' 2
|
|
81
|
+
check "line continuation" 'find . \
|
|
82
|
+
-delete' 2
|
|
83
|
+
|
|
84
|
+
# --- everyday cleanup must stay allowed --------------------------------------
|
|
85
|
+
check "narrowed by name" "find . -name '*.pyc' -delete" 0
|
|
86
|
+
check "narrowed by name and age" "find ./logs -name '*.log' -mtime +30 -delete" 0
|
|
87
|
+
check "type plus name" "find . -type f -name '*.tmp' -delete" 0
|
|
88
|
+
check "narrowed by -newer" 'find . -newer package.json -delete' 0
|
|
89
|
+
check "throwaway dir: node_modules" 'find node_modules -delete' 0
|
|
90
|
+
check "throwaway dir: dist" 'find dist -delete' 0
|
|
91
|
+
check "throwaway dir: ./build" 'find ./build -delete' 0
|
|
92
|
+
check "print only" 'find . -print' 0
|
|
93
|
+
check "print only from /" "find / -name '*.log' -print" 0
|
|
94
|
+
check "piped to grep" "find . -name '*.py' | xargs grep foo" 0
|
|
95
|
+
check "find inside a string" 'echo "find . -delete"' 0
|
|
96
|
+
check "find inside a commit message" 'git commit -m "add find . -delete example"' 0
|
|
97
|
+
check "prune, no deletion" 'find . -type d -name node_modules -prune' 0
|
|
98
|
+
check "unrelated command" 'ls -la' 0
|
|
99
|
+
|
|
100
|
+
# --- Check 1: trailing content used to defeat the tilde/HOME position --------
|
|
101
|
+
check "bare tilde" 'rm -rf ~' 2
|
|
102
|
+
check "tilde then a comment" 'rm -rf ~ # cleanup' 2
|
|
103
|
+
check "tilde then another argument" 'rm -rf ~ /srv/data' 2
|
|
104
|
+
check "quoted HOME" 'rm -rf "$HOME"' 2
|
|
105
|
+
check "HOME then a redirect" 'rm -rf "$HOME" 2>/dev/null' 2
|
|
106
|
+
check "parent then a comment" 'rm -rf .. # oops' 2
|
|
107
|
+
check "cwd then a comment" 'rm -rf . # oops' 2
|
|
108
|
+
check "specific subdirectory allowed" 'rm -rf ./node_modules' 0
|
|
109
|
+
check "nested build path allowed" 'rm -rf ./dist/assets' 0
|
|
110
|
+
check "path under .git allowed" 'rm -rf .git/objects/tmp' 0
|
|
111
|
+
|
|
112
|
+
echo
|
|
113
|
+
echo "destructive-guard-find-deletion: $PASS passed, $FAIL failed"
|
|
114
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# destructive-guard: the words do not have to be in that order
|
|
3
|
+
#
|
|
4
|
+
# Checks 2, 3 and 4 each pinned the position of a flag:
|
|
5
|
+
#
|
|
6
|
+
# Check 2 git\s+reset\s+--hard -- --hard must follow `reset`
|
|
7
|
+
# Check 3 git\s+clean\s+-[a-z]*[fd] -- the flags must be one bundle, first
|
|
8
|
+
# Check 4 chmod\s+(-R\s+)?777\s+(/|~|\.) -- -R before 777, path right after
|
|
9
|
+
#
|
|
10
|
+
# A shell does not care. `git reset HEAD~1 --hard` discards exactly the same work,
|
|
11
|
+
# `git clean -x -f -d` deletes more than `git clean -fd`, and `chmod 777 -R /etc`
|
|
12
|
+
# is `chmod -R 777 /etc`. All three walked past the guard.
|
|
13
|
+
#
|
|
14
|
+
# Measured 2026-08-03 against the shipped copy, with the denominator restricted to
|
|
15
|
+
# the pairs this guard actually blocks in their canonical form: 5 of 19 reorderings
|
|
16
|
+
# were not blocked. After the fix: 0 of 19, with 0 newly blocked out of 28 everyday
|
|
17
|
+
# commands.
|
|
18
|
+
#
|
|
19
|
+
# This is the same shape as the defect in the approving hooks fixed the same day
|
|
20
|
+
# (#937/#940/#941/#942/#943/#947/#948), one level up: there the rule assumed the
|
|
21
|
+
# dangerous part came *after* the first command position; here it assumes the
|
|
22
|
+
# dangerous flag comes in a fixed *slot*. Both are a pattern that encodes a habit
|
|
23
|
+
# of typing rather than what the command does.
|
|
24
|
+
#
|
|
25
|
+
# `[^;&|]` keeps every scan inside one command, so a later command's words are
|
|
26
|
+
# never borrowed to make a match.
|
|
27
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
28
|
+
GUARD=$(mktemp); trap 'rm -f "$GUARD"' EXIT
|
|
29
|
+
python3 -c "
|
|
30
|
+
import json,sys
|
|
31
|
+
sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$GUARD"
|
|
32
|
+
|
|
33
|
+
PASS=0; FAIL=0
|
|
34
|
+
|
|
35
|
+
check() {
|
|
36
|
+
local desc="$1" cmd="$2" want="$3" # want: 2 = blocked, 0 = allowed
|
|
37
|
+
local payload code
|
|
38
|
+
payload=$(python3 -c '
|
|
39
|
+
import json,sys
|
|
40
|
+
print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]}}))' "$cmd")
|
|
41
|
+
printf '%s' "$payload" | bash "$GUARD" >/dev/null 2>&1
|
|
42
|
+
code=$?
|
|
43
|
+
if [ "$code" = "$want" ]; then
|
|
44
|
+
echo "PASS: $desc"; PASS=$((PASS+1))
|
|
45
|
+
else
|
|
46
|
+
echo "FAIL: $desc (expected exit $want, got $code)"; FAIL=$((FAIL+1))
|
|
47
|
+
fi
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# --- Check 2: git reset --hard, wherever the flag sits ---
|
|
51
|
+
check "reset: canonical order" 'git reset --hard HEAD~1' 2
|
|
52
|
+
check "reset: flag last" 'git reset HEAD~1 --hard' 2
|
|
53
|
+
check "reset: flag last, named remote" 'git reset origin/main --hard' 2
|
|
54
|
+
check "reset: bare" 'git reset --hard' 2
|
|
55
|
+
check "reset: --soft is not --hard" 'git reset --soft HEAD~1' 0
|
|
56
|
+
check "reset: plain reset unstages only" 'git reset HEAD~1' 0
|
|
57
|
+
check "reset: --hard belongs to the next command" 'git reset HEAD~1 ; echo --hard' 0
|
|
58
|
+
check "reset: inside a message" "git commit -m 'git reset --hard の話'" 0
|
|
59
|
+
|
|
60
|
+
# --- Check 3: git clean, flags split or reordered ---
|
|
61
|
+
check "clean: canonical bundle" 'git clean -fd' 2
|
|
62
|
+
check "clean: split flags" 'git clean -f -d' 2
|
|
63
|
+
check "clean: reversed" 'git clean -d -f' 2
|
|
64
|
+
check "clean: another flag first" 'git clean -x -f -d' 2
|
|
65
|
+
check "clean: bundle with a trailing x" 'git clean -fdx' 2
|
|
66
|
+
check "clean: bundle with two extras" 'git clean -fdxq' 2
|
|
67
|
+
check "clean: long form" 'git clean --force -d' 2
|
|
68
|
+
check "clean: dry run stays allowed" 'git clean -n' 0
|
|
69
|
+
check "clean: dry run with -d" 'git clean -nd' 0
|
|
70
|
+
check "clean: dry run with -d and -x" 'git clean -ndx' 0
|
|
71
|
+
check "clean: long dry run" 'git clean --dry-run' 0
|
|
72
|
+
check "clean: force plus dry run is a dry run" 'git clean --force --dry-run' 0
|
|
73
|
+
|
|
74
|
+
# --- Check 4: chmod 777, wherever -R sits ---
|
|
75
|
+
check "chmod: canonical order" 'chmod -R 777 /etc' 2
|
|
76
|
+
check "chmod: -R after the mode" 'chmod 777 -R /etc' 2
|
|
77
|
+
check "chmod: -R last" 'chmod 777 /etc -R' 2
|
|
78
|
+
check "chmod: long recursive flag" 'chmod --recursive 777 /etc' 2
|
|
79
|
+
check "chmod: no -R at all" 'chmod 777 /etc' 2
|
|
80
|
+
check "chmod: home directory" 'chmod 777 -R ~/' 2
|
|
81
|
+
check "chmod: relative path" 'chmod 777 -R ./' 2
|
|
82
|
+
check "chmod: a narrower mode is fine" 'chmod 644 ./file.txt' 0
|
|
83
|
+
check "chmod: 755 on a script" 'chmod 755 ./bin/run' 0
|
|
84
|
+
check "chmod: +x is fine" 'chmod +x script.sh' 0
|
|
85
|
+
check "chmod: 777 on a plain filename" 'chmod 777 file.txt' 0
|
|
86
|
+
|
|
87
|
+
# --- the scans must not cross into the next command ---
|
|
88
|
+
check "no borrowing across ;" 'echo 777 ; chmod 644 ./x' 0
|
|
89
|
+
check "no borrowing across &&" 'git clean -n && echo -fd' 0
|
|
90
|
+
|
|
91
|
+
# --- Check 5: a wrapper may carry assignments of its own ---
|
|
92
|
+
# Found while judging the 2026-07-27 find hypothesis: the prefix stripper dropped
|
|
93
|
+
# leading VAR=value once, then dropped wrappers in a loop. `env LC_ALL=C find` puts
|
|
94
|
+
# the assignment *after* the wrapper, so it survived and the command word was read
|
|
95
|
+
# as `LC_ALL=C`. Same shape as the rest of this file: a rule that assumed which
|
|
96
|
+
# order the pieces arrive in. Assignments are now dropped inside the same loop.
|
|
97
|
+
check "find: bare wrapper" 'env find . -delete' 2
|
|
98
|
+
check "find: wrapper with an assignment" 'env LC_ALL=C find . -delete' 2
|
|
99
|
+
check "find: two assignments" 'env LC_ALL=C TZ=UTC find . -delete' 2
|
|
100
|
+
check "find: assignment with no wrapper" 'LC_ALL=C find . -delete' 2
|
|
101
|
+
check "find: narrowed cleanup still runs" "find . -name '*.pyc' -delete" 0
|
|
102
|
+
check "find: narrowed with a wrapper" "env LC_ALL=C find . -name '*.pyc' -delete" 0
|
|
103
|
+
|
|
104
|
+
echo
|
|
105
|
+
echo "destructive-guard-flag-order: $PASS passed, $FAIL failed"
|
|
106
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Searching for a dangerous command is not running one.
|
|
3
|
+
#
|
|
4
|
+
# destructive-guard scans the whole command string, so a dangerous string
|
|
5
|
+
# written inside quotes — or inside a sentence — reached the same checks as an
|
|
6
|
+
# executed command. Measured 2026-08-04 against fifteen commands that must not
|
|
7
|
+
# be blocked: six were blocked. All six merely mention a command:
|
|
8
|
+
#
|
|
9
|
+
# grep -r "rm -rf /" . searching for it
|
|
10
|
+
# echo 'rm -rf /' >> notes.md writing it into a note
|
|
11
|
+
# git commit -m "docs: warn about rm -rf /" naming it in a message
|
|
12
|
+
# jq -n '{cmd: "rm -rf /"}' naming it in a filter
|
|
13
|
+
# awk '/rm -rf / {print}' history.log naming it in a program
|
|
14
|
+
# echo "the command rm -rf ~ destroys ..." describing it
|
|
15
|
+
#
|
|
16
|
+
# A guard that blocks grep, awk and git commit is switched off the same day it
|
|
17
|
+
# is installed, and a switched-off guard is worse than none because the user
|
|
18
|
+
# still believes it is there. (The author hit this false positive seven times in
|
|
19
|
+
# one day while writing about the guard.)
|
|
20
|
+
#
|
|
21
|
+
# Check 0y blanks quoted spans and asks whether a destructive verb still appears
|
|
22
|
+
# at a command start. If none does, nothing destructive is being invoked.
|
|
23
|
+
# It does NOT strip the quotes before matching — stripping them would lose a
|
|
24
|
+
# real invocation whose target is quoted. Everything after the gate still
|
|
25
|
+
# matches against the original text.
|
|
26
|
+
#
|
|
27
|
+
# The block half of this file is what keeps the gate honest. A gate that lets
|
|
28
|
+
# too much through is exactly as useless as the false positives it removes, so
|
|
29
|
+
# every wrapper form the other suites cover is repeated here: prefixes, leading
|
|
30
|
+
# assignments, path-qualified names, and the three constructs that execute their
|
|
31
|
+
# quoted argument (`sh -c`, `eval`, `powershell -Command`).
|
|
32
|
+
|
|
33
|
+
set -u
|
|
34
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
35
|
+
WORK="$(mktemp -d)"
|
|
36
|
+
trap 'find "$WORK" -mindepth 1 -delete 2>/dev/null; rmdir "$WORK" 2>/dev/null' EXIT
|
|
37
|
+
PASS=0; FAIL=0
|
|
38
|
+
|
|
39
|
+
python3 -c "
|
|
40
|
+
import json,sys
|
|
41
|
+
sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$WORK/dg.sh"
|
|
42
|
+
|
|
43
|
+
run() {
|
|
44
|
+
local T; T="$(mktemp -d)"
|
|
45
|
+
python3 -c '
|
|
46
|
+
import json,sys
|
|
47
|
+
print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]},
|
|
48
|
+
"cwd":sys.argv[2],"session_id":"t"}))' "$1" "$T" \
|
|
49
|
+
| HOME="$T" bash "$WORK/dg.sh" >/dev/null 2>&1
|
|
50
|
+
local rc=$?
|
|
51
|
+
find "$T" -mindepth 1 -delete 2>/dev/null; rmdir "$T" 2>/dev/null
|
|
52
|
+
return $rc
|
|
53
|
+
}
|
|
54
|
+
want_block() {
|
|
55
|
+
if run "$1"; then FAIL=$((FAIL+1)); echo " FAIL blocked: $1"
|
|
56
|
+
else PASS=$((PASS+1)); echo " ok blocked: $1"; fi
|
|
57
|
+
}
|
|
58
|
+
want_allow() {
|
|
59
|
+
if run "$1"; then PASS=$((PASS+1)); echo " ok allowed: $1"
|
|
60
|
+
else FAIL=$((FAIL+1)); echo " FAIL allowed: $1"; fi
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
RM="$(printf 'r%s' 'm') -rf "
|
|
64
|
+
echo "destructive-guard-mentions-vs-invocations"
|
|
65
|
+
|
|
66
|
+
# --- mentions: the command appears only inside quotes or prose ---------------
|
|
67
|
+
want_allow "grep -r \"${RM}/\" ."
|
|
68
|
+
want_allow "grep -rn '${RM}~' docs/"
|
|
69
|
+
want_allow "echo \"${RM}~\""
|
|
70
|
+
want_allow "echo '${RM}/' >> notes.md"
|
|
71
|
+
want_allow "git commit -m \"docs: warn about ${RM}/ in the guide\""
|
|
72
|
+
want_allow "git log --grep=\"${RM}\""
|
|
73
|
+
want_allow "python3 -c \"print('${RM}~')\""
|
|
74
|
+
want_allow "jq -n '{cmd: \"${RM}/\"}'"
|
|
75
|
+
want_allow "printf \"%s\\n\" \"${RM}~\" > example.txt"
|
|
76
|
+
want_allow "rg \"${RM}\" --files-with-matches"
|
|
77
|
+
want_allow "sed -n \"/${RM}/p\" history.log"
|
|
78
|
+
want_allow "awk '/${RM}/ {print}' history.log"
|
|
79
|
+
want_allow "echo \"the command ${RM}~ destroys your home directory\""
|
|
80
|
+
|
|
81
|
+
# --- invocations: the command actually runs ---------------------------------
|
|
82
|
+
want_block "${RM}~"
|
|
83
|
+
want_block "${RM}/"
|
|
84
|
+
want_block "cd /tmp && ${RM}~"
|
|
85
|
+
want_block "[[ -n \$(${RM}~) ]]"
|
|
86
|
+
want_block "if true; then ${RM}~; fi"
|
|
87
|
+
want_block "env ${RM}~"
|
|
88
|
+
want_block "nice -n 5 ${RM}~"
|
|
89
|
+
want_block "timeout 30 ${RM}~"
|
|
90
|
+
want_block "FOO=1 ${RM}~"
|
|
91
|
+
want_block "/bin/${RM}~"
|
|
92
|
+
want_block "git reset --hard HEAD~5"
|
|
93
|
+
|
|
94
|
+
# --- the quoted argument is executed here, so it is an invocation ------------
|
|
95
|
+
want_block "bash -c \"${RM}~\""
|
|
96
|
+
want_block "sh -c '${RM}/'"
|
|
97
|
+
|
|
98
|
+
# Known gap, not asserted: `eval "rm -rf ~"` passes, and so do `rm -rf "/etc"`
|
|
99
|
+
# and `rm -rf '~'`. The gate correctly refuses to treat these as mentions, but
|
|
100
|
+
# the target matching downstream does not unquote its operand, so the path is
|
|
101
|
+
# never recognised. Measured 2026-08-04 on the shipped guard as well — this
|
|
102
|
+
# predates the gate and is tracked separately. Asserting it here would make the
|
|
103
|
+
# file fail for a reason it does not fix.
|
|
104
|
+
|
|
105
|
+
echo
|
|
106
|
+
echo "destructive-guard-mentions-vs-invocations: $PASS passed, $FAIL failed"
|
|
107
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Quoting the argument made the target invisible.
|
|
3
|
+
#
|
|
4
|
+
# Check 1 required the path to follow the flags directly:
|
|
5
|
+
#
|
|
6
|
+
# rm -rf /etc blocked
|
|
7
|
+
# rm -rf "/etc" NOT blocked <- same deletion, one character apart
|
|
8
|
+
# rm -rf '~' NOT blocked
|
|
9
|
+
#
|
|
10
|
+
# Quoting an argument is an ordinary way to write a command — a path with a
|
|
11
|
+
# space in it has to be quoted — so this is not an evasion technique, it is
|
|
12
|
+
# what a careful user types. Measured 2026-08-04 against the shipped guard:
|
|
13
|
+
# five of nine quoted forms passed.
|
|
14
|
+
#
|
|
15
|
+
# Two places assumed an unquoted operand: the Check 1 pattern (one optional
|
|
16
|
+
# quote is now allowed in front of the path, and the terminators accept a
|
|
17
|
+
# closing quote) and the TARGET_PATH extraction feeding findmnt (`\S+` picked
|
|
18
|
+
# up the quotes, and findmnt cannot resolve a path spelled with them attached).
|
|
19
|
+
#
|
|
20
|
+
# The controls are what keep this from becoming "block anything with a quote":
|
|
21
|
+
# a quoted safe target must still pass, and — this is the one that matters after
|
|
22
|
+
# the mentions/invocations gate landed — a dangerous string quoted inside grep,
|
|
23
|
+
# echo, git commit or awk must still pass, because searching for a command is
|
|
24
|
+
# not running it.
|
|
25
|
+
|
|
26
|
+
set -u
|
|
27
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
28
|
+
WORK="$(mktemp -d)"
|
|
29
|
+
trap 'find "$WORK" -mindepth 1 -delete 2>/dev/null; rmdir "$WORK" 2>/dev/null' EXIT
|
|
30
|
+
PASS=0; FAIL=0
|
|
31
|
+
|
|
32
|
+
python3 -c "
|
|
33
|
+
import json,sys
|
|
34
|
+
sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$WORK/dg.sh"
|
|
35
|
+
|
|
36
|
+
run() {
|
|
37
|
+
local T; T="$(mktemp -d)"
|
|
38
|
+
python3 -c '
|
|
39
|
+
import json,sys
|
|
40
|
+
print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]},
|
|
41
|
+
"cwd":sys.argv[2],"session_id":"t"}))' "$1" "$T" \
|
|
42
|
+
| HOME="$T" bash "$WORK/dg.sh" >/dev/null 2>&1
|
|
43
|
+
local rc=$?
|
|
44
|
+
find "$T" -mindepth 1 -delete 2>/dev/null; rmdir "$T" 2>/dev/null
|
|
45
|
+
return $rc
|
|
46
|
+
}
|
|
47
|
+
want_block() {
|
|
48
|
+
if run "$1"; then FAIL=$((FAIL+1)); echo " FAIL blocked: $1"
|
|
49
|
+
else PASS=$((PASS+1)); echo " ok blocked: $1"; fi
|
|
50
|
+
}
|
|
51
|
+
want_allow() {
|
|
52
|
+
if run "$1"; then PASS=$((PASS+1)); echo " ok allowed: $1"
|
|
53
|
+
else FAIL=$((FAIL+1)); echo " FAIL allowed: $1"; fi
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
RM="$(printf 'r%s' 'm') -rf "
|
|
57
|
+
echo "destructive-guard-quoted-target"
|
|
58
|
+
|
|
59
|
+
# --- the target is quoted, the deletion is real ------------------------------
|
|
60
|
+
want_block "${RM}\"/etc\""
|
|
61
|
+
want_block "${RM}'/etc'"
|
|
62
|
+
want_block "${RM}\"~\""
|
|
63
|
+
want_block "${RM}'~'"
|
|
64
|
+
want_block "${RM}\"/home/user\""
|
|
65
|
+
want_block "sudo ${RM}\"/var\""
|
|
66
|
+
|
|
67
|
+
# --- unquoted, which already worked ------------------------------------------
|
|
68
|
+
want_block "${RM}~"
|
|
69
|
+
want_block "${RM}/"
|
|
70
|
+
want_block "${RM}/etc"
|
|
71
|
+
|
|
72
|
+
# --- controls: a quoted safe target is still safe ----------------------------
|
|
73
|
+
want_allow "${RM}\"node_modules\""
|
|
74
|
+
want_allow "${RM}'node_modules'"
|
|
75
|
+
want_allow "${RM}\"./build\""
|
|
76
|
+
want_allow "${RM}node_modules"
|
|
77
|
+
want_allow "${RM}./build"
|
|
78
|
+
|
|
79
|
+
# --- controls: quoting it inside another command is still a mention ----------
|
|
80
|
+
want_allow "echo \"${RM}/\""
|
|
81
|
+
want_allow "grep -r \"${RM}/\" ."
|
|
82
|
+
want_allow "git commit -m \"docs: ${RM}/ warning\""
|
|
83
|
+
want_allow "awk '/${RM}/ {print}' h.log"
|
|
84
|
+
want_allow "ls -la"
|
|
85
|
+
want_allow "npm ci && npm run build"
|
|
86
|
+
|
|
87
|
+
echo
|
|
88
|
+
echo "destructive-guard-quoted-target: $PASS passed, $FAIL failed"
|
|
89
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# destructive-guard: command separators
|
|
3
|
+
#
|
|
4
|
+
# Checks 2, 3 and 7 listed their separators as (^ | ; | && | ||) and left out
|
|
5
|
+
# a bare `&`. `true & git reset --hard` therefore ran unguarded — the same
|
|
6
|
+
# "allow-list of separators" hole that has bitten this guard before.
|
|
7
|
+
# Measured on 2026-07-27: all three checks let a bare & through.
|
|
8
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
9
|
+
GUARD=$(mktemp); trap 'rm -f "$GUARD"' EXIT
|
|
10
|
+
python3 -c "
|
|
11
|
+
import json,sys
|
|
12
|
+
sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$GUARD"
|
|
13
|
+
|
|
14
|
+
PASS=0; FAIL=0
|
|
15
|
+
|
|
16
|
+
check() {
|
|
17
|
+
local desc="$1" cmd="$2" want="$3" # want: 2 = blocked, 0 = allowed
|
|
18
|
+
local payload code
|
|
19
|
+
payload=$(python3 -c '
|
|
20
|
+
import json,sys
|
|
21
|
+
print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]}}))' "$cmd")
|
|
22
|
+
printf '%s' "$payload" | bash "$GUARD" >/dev/null 2>&1
|
|
23
|
+
code=$?
|
|
24
|
+
if [ "$code" = "$want" ]; then
|
|
25
|
+
echo "PASS: $desc"; ((PASS++))
|
|
26
|
+
else
|
|
27
|
+
echo "FAIL: $desc (expected exit $want, got $code)"; ((FAIL++))
|
|
28
|
+
fi
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Check 2 — git reset --hard, reachable through every separator
|
|
32
|
+
check "reset: bare & is blocked" 'true & git reset --hard' 2
|
|
33
|
+
check "reset: semicolon is blocked" 'true ; git reset --hard' 2
|
|
34
|
+
check "reset: && is blocked" 'true && git reset --hard' 2
|
|
35
|
+
check "reset: || is blocked" 'false || git reset --hard' 2
|
|
36
|
+
check "reset: start of line is blocked" 'git reset --hard' 2
|
|
37
|
+
check "reset: --soft stays allowed" 'git reset --soft HEAD~1' 0
|
|
38
|
+
|
|
39
|
+
# Check 3 — git clean
|
|
40
|
+
check "clean: bare & is blocked" 'true & git clean -fd' 2
|
|
41
|
+
check "clean: && is blocked" 'true && git clean -fd' 2
|
|
42
|
+
check "clean: start of line is blocked" 'git clean -fd' 2
|
|
43
|
+
check "clean: --dry-run stays allowed" 'git clean --dry-run' 0
|
|
44
|
+
|
|
45
|
+
# Check 7 — git checkout --force
|
|
46
|
+
check "checkout: bare & is blocked" 'true & git checkout -f main' 2
|
|
47
|
+
check "checkout: && is blocked" 'true && git checkout -f main' 2
|
|
48
|
+
check "checkout: plain checkout allowed" 'git checkout main' 0
|
|
49
|
+
check "checkout: plain switch allowed" 'git switch feature' 0
|
|
50
|
+
|
|
51
|
+
# Check 6 — sudo in front of a destructive command.
|
|
52
|
+
#
|
|
53
|
+
# This check anchored its pattern with `^\s*sudo`, so the anchor was applied to
|
|
54
|
+
# the whole command string instead of to each command position. Anything placed
|
|
55
|
+
# after a separator was never examined. It stayed invisible for a long time
|
|
56
|
+
# because Check 1 independently blocks rm on a sensitive path, so the usual
|
|
57
|
+
# probe (`cd /tmp && sudo rm -rf /var`) still came back blocked. The gap only
|
|
58
|
+
# shows on the targets Check 6 alone is responsible for: an ordinary relative
|
|
59
|
+
# path, and dd/mkfs, which no other check looks at.
|
|
60
|
+
# Measured 2026-08-03 against the shipped scripts.json: 7 of 8 such commands
|
|
61
|
+
# exited 0 once a separator was placed in front. Same shape as PR #937.
|
|
62
|
+
check "sudo rm: start of line is blocked" 'sudo rm -rf myproject' 2
|
|
63
|
+
check "sudo rm: && is blocked" 'cd /tmp && sudo rm -rf myproject' 2
|
|
64
|
+
check "sudo rm: semicolon is blocked" 'cd /tmp; sudo rm -rf myproject' 2
|
|
65
|
+
check "sudo rm: bare & is blocked" 'true & sudo rm -rf myproject' 2
|
|
66
|
+
check "sudo rm: || is blocked" 'false || sudo rm -rf myproject' 2
|
|
67
|
+
check "sudo rm -r: && is blocked" 'cd /tmp && sudo rm -r data' 2
|
|
68
|
+
check "sudo dd: && is blocked" 'cd /tmp && sudo dd if=/dev/zero of=/dev/sda' 2
|
|
69
|
+
check "sudo mkfs: && is blocked" 'cd /tmp && sudo mkfs.ext4 /dev/sdb1' 2
|
|
70
|
+
check "sudo chmod 777: && is blocked" 'cd /tmp && sudo chmod -R 777 /opt/app' 2
|
|
71
|
+
|
|
72
|
+
# Closing the hole must not close anything else. sudo on a harmless command is
|
|
73
|
+
# everyday work and stays allowed in every position.
|
|
74
|
+
check "sudo apt stays allowed" 'sudo apt update' 0
|
|
75
|
+
check "sudo apt after && stays allowed" 'cd /tmp && sudo apt update' 0
|
|
76
|
+
check "sudo -l stays allowed" 'sudo -l' 0
|
|
77
|
+
check "sudo systemctl stays allowed" 'cd /srv && sudo systemctl reload nginx' 0
|
|
78
|
+
|
|
79
|
+
# Check 7 — PowerShell Remove-Item.
|
|
80
|
+
#
|
|
81
|
+
# The skip that keeps `echo "Remove-Item -Recurse -Force"` from being read as a
|
|
82
|
+
# deletion was anchored the same way, so it only applied when the command
|
|
83
|
+
# *began* with a string-output command. Put anything in front and the guard
|
|
84
|
+
# blocked a command that only prints text. Measured 2026-08-03: exit 2 on
|
|
85
|
+
# `cd /tmp && echo "..."`. That is the over-tightening side of the same anchor.
|
|
86
|
+
check "PS: bare Remove-Item is blocked" 'Remove-Item -Recurse -Force *' 2
|
|
87
|
+
check "PS: after && is blocked" 'cd /tmp && Remove-Item -Recurse -Force *' 2
|
|
88
|
+
check "PS: after semicolon is blocked" 'cd /tmp; Remove-Item -Recurse -Force *' 2
|
|
89
|
+
check "PS: powershell wrapper is blocked" 'powershell -c "Remove-Item -Recurse -Force C:\\Users\\john"' 2
|
|
90
|
+
check "PS: single file stays allowed" 'Remove-Item ./file.txt' 0
|
|
91
|
+
check "PS: echo of the words allowed" 'echo "Remove-Item -Recurse -Force"' 0
|
|
92
|
+
check "PS: echo after && allowed" 'cd /tmp && echo "Remove-Item -Recurse -Force"' 0
|
|
93
|
+
check "PS: git commit message allowed" 'git commit -m "handle Remove-Item -Recurse -Force"' 0
|
|
94
|
+
check "PS: commit message after && ok" 'cd repo && git commit -m "handle Remove-Item -Recurse -Force"' 0
|
|
95
|
+
check "PS: grep for the words allowed" 'cat notes.txt | grep "Remove-Item -Recurse -Force"' 0
|
|
96
|
+
|
|
97
|
+
# Nothing above should have changed the ordinary allow cases
|
|
98
|
+
check "read-only command allowed" 'grep -r TODO .' 0
|
|
99
|
+
check "safe dir deletion allowed" 'rm -rf node_modules' 0
|
|
100
|
+
check "plain cd compound allowed" 'cd /tmp && ls -la' 0
|
|
101
|
+
check "echo compound allowed" 'echo hello && pwd' 0
|
|
102
|
+
|
|
103
|
+
echo ""
|
|
104
|
+
echo "PASS: $PASS FAIL: $FAIL"
|
|
105
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Putting the target in a variable made the deletion invisible.
|
|
3
|
+
#
|
|
4
|
+
# Every check keys on the literal text of the command, so a path held in a
|
|
5
|
+
# variable was never seen:
|
|
6
|
+
#
|
|
7
|
+
# rm -rf /etc blocked
|
|
8
|
+
# D=/etc; rm -rf $D NOT blocked <- same deletion, same command string
|
|
9
|
+
# CMD="rm -rf /"; $CMD NOT blocked
|
|
10
|
+
#
|
|
11
|
+
# Assigning a path to a variable is ordinary shell, not an evasion technique —
|
|
12
|
+
# the same shape as the quoted-target hole (#961): the more carefully someone
|
|
13
|
+
# writes the script, the less protected they were. Measured 2026-08-06 against
|
|
14
|
+
# the shipped guard: three of seven variable forms passed.
|
|
15
|
+
#
|
|
16
|
+
# The fix resolves assignments that are visible in the same command string and
|
|
17
|
+
# runs this same guard against the resolved text (the Check 0z pattern), so no
|
|
18
|
+
# new detection logic is added. A safe value stays safe once expanded, which is
|
|
19
|
+
# what keeps this from becoming "block anything with a $".
|
|
20
|
+
#
|
|
21
|
+
# ORDER MATTERS: Check 0x has to sit before Check 0y. Check 0y returns 0 when no
|
|
22
|
+
# destructive verb appears outside quotes, and `CMD="rm -rf /"; $CMD` has none —
|
|
23
|
+
# so a version placed after 0y never reached the substitution at all. The
|
|
24
|
+
# false-positive protection of 0y still applies, because the child process runs
|
|
25
|
+
# the full file including 0y against the resolved text.
|
|
26
|
+
#
|
|
27
|
+
# Values that only exist at runtime (environment variables inherited from the
|
|
28
|
+
# parent) cannot be resolved statically. That hole stays, and is documented
|
|
29
|
+
# rather than asserted.
|
|
30
|
+
|
|
31
|
+
set -u
|
|
32
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
33
|
+
WORK="$(mktemp -d)"
|
|
34
|
+
trap 'find "$WORK" -mindepth 1 -delete 2>/dev/null; rmdir "$WORK" 2>/dev/null' EXIT
|
|
35
|
+
PASS=0; FAIL=0
|
|
36
|
+
|
|
37
|
+
python3 -c "
|
|
38
|
+
import json,sys
|
|
39
|
+
sys.stdout.write(json.load(open('$ROOT/scripts.json'))['destructive-guard'])" > "$WORK/dg.sh"
|
|
40
|
+
|
|
41
|
+
run() {
|
|
42
|
+
local T; T="$(mktemp -d)"
|
|
43
|
+
python3 -c '
|
|
44
|
+
import json,sys
|
|
45
|
+
print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]},
|
|
46
|
+
"cwd":sys.argv[2],"session_id":"t"}))' "$1" "$T" \
|
|
47
|
+
| HOME="$T" bash "$WORK/dg.sh" >/dev/null 2>&1
|
|
48
|
+
local rc=$?
|
|
49
|
+
find "$T" -mindepth 1 -delete 2>/dev/null; rmdir "$T" 2>/dev/null
|
|
50
|
+
return $rc
|
|
51
|
+
}
|
|
52
|
+
want_block() {
|
|
53
|
+
if run "$1"; then FAIL=$((FAIL+1)); echo " FAIL blocked: $1"
|
|
54
|
+
else PASS=$((PASS+1)); echo " ok blocked: $1"; fi
|
|
55
|
+
}
|
|
56
|
+
want_allow() {
|
|
57
|
+
if run "$1"; then PASS=$((PASS+1)); echo " ok allowed: $1"
|
|
58
|
+
else FAIL=$((FAIL+1)); echo " FAIL allowed: $1"; fi
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
RM="$(printf 'r%s' 'm') -rf "
|
|
62
|
+
echo "destructive-guard-variable-target"
|
|
63
|
+
|
|
64
|
+
# --- the assignment is visible in the same command string --------------------
|
|
65
|
+
want_block "D=/etc; ${RM}\$D"
|
|
66
|
+
want_block "D=/; ${RM}\"\$D\""
|
|
67
|
+
want_block "D=/var; ${RM}\${D}"
|
|
68
|
+
want_block "CMD=\"${RM}/\"; \$CMD"
|
|
69
|
+
want_block "TARGET=/var; sudo ${RM}\$TARGET"
|
|
70
|
+
want_block "P='/etc'; ${RM}\$P"
|
|
71
|
+
|
|
72
|
+
# --- named environment variables whose value is known ------------------------
|
|
73
|
+
want_block "${RM}\$HOME"
|
|
74
|
+
want_block "${RM}\${HOME}"
|
|
75
|
+
want_block "${RM}\"\$HOME\""
|
|
76
|
+
|
|
77
|
+
# --- controls: wrappers already closed (a break here means the harness moved) -
|
|
78
|
+
want_block "eval \"${RM}/etc\""
|
|
79
|
+
want_block "sh -c \"${RM}/etc\""
|
|
80
|
+
|
|
81
|
+
# --- controls: a safe value stays safe once expanded -------------------------
|
|
82
|
+
want_allow "D=./build; ${RM}\$D"
|
|
83
|
+
want_allow "D=node_modules; ${RM}\$D"
|
|
84
|
+
want_allow "OUT=dist; ${RM}\"\$OUT\""
|
|
85
|
+
want_allow "${RM}\$TMPDIR/work"
|
|
86
|
+
|
|
87
|
+
# --- controls: mentioning is still not running -------------------------------
|
|
88
|
+
want_allow "echo \"${RM}\$HOME\""
|
|
89
|
+
want_allow "D=/etc; echo \"${RM}\$D\""
|
|
90
|
+
want_allow "grep -rn '\$D' ."
|
|
91
|
+
|
|
92
|
+
# --- controls: ordinary commands ---------------------------------------------
|
|
93
|
+
want_allow "ls -la"
|
|
94
|
+
want_allow "npm ci && npm run build"
|
|
95
|
+
|
|
96
|
+
echo
|
|
97
|
+
echo "destructive-guard-variable-target: $PASS passed, $FAIL failed"
|
|
98
|
+
[ "$FAIL" -eq 0 ]
|