Repository navigation
[bug] Dangerous-command rules miss standard forms: git push -f, dd with reordered args, systemctl poweroff, dead ":>" regex #130
Description
Activity
This issue was auto-closed. All issues from new contributors are auto-closed by default.
Maintainers review auto-closed issues daily and reopen worthwhile ones. Issues that do not meet the quality bar in CONTRIBUTING.md will not be reopened or receive a reply.
If a maintainer replies
lgtmion one of your issues, your future issues will stay open. If a maintainer replieslgtm, your future issues and PRs will stay open. The command must be at the start of the reply (optionally after one or more@usernamementions) or at the end.See CONTRIBUTING.md.
#209 合并后,在当前 main(519e4de4)上把本 issue 列的几条逐条实测了一遍,用的是analyzeCommandPolicy 实跑,不是读码推断。另外发现一个反向问题。
#209 已修
- copy-device 支持 bs= / of= 前置,dd bs=4M if=disk.img of=/dev/sda 与 dd of=/dev/sda if=/dev/zero 均能识别
- destructive-git 识别 -f 与 --force-with-lease=
- truncate-device 的 � 定位问题已修,:> /dev/sda、: >/dev/sda、: > /dev/sda 均能识别
仍未修
- git push origin +main:+refspec 强推语法仍不在 destructive-git 模式内
- git -C repo reset --hard 与 git -c x=y push --force:模式要求子命令紧接 git,全局选项仍可绕过全部三条 git 规则
- systemctl poweroff / systemctl halt / init 0:command-policy.ts:3 的 DANGEROUS_LIFECYCLE_COMMANDS 仍只有 reboot 与 shutdown
这三组对应本 issue 原文的第 2、3、4 条中 #209 未覆盖的部分。
一个反向问题(漏报变误报)
command-policy.ts:97 的 copy-device 现在是 /\bdd\b[^;&|\n]*\bif=/iu,只检查 if= 是否在场,不看 of= 指向哪。结果是 dd if=image of=out.img 这种把镜像写进普通文件的操作也被判危险。
在默认 bypass 预设下这个误报一样影响体验:一次多余确认,而且方向与 #209 想解决的相反。
要同时满足两边,判据需要求 if= 或 of= 之一指向 /dev/,而不是只要 if= 在场。
本 issue 的 Expected behavior 里 match of=/dev/ anywhere in dd args 接近这个方向,但只加 of=/dev/ 会漏掉 dd if=/dev/zero of=disk.img 这种读设备的方向,所以两侧都要查。@Zi-Yi-Ming 按你的复测结果把剩余三组和一个反向问题都改了,分支在
hobostay:fix/command-policy-gap-closures(对比视图:main...hobostay:Step-Code:fix/command-policy-gap-closures )。API 创建 PR 被权限拒绝(CreatePullRequestpermission denied),所以先贴分支,欢迎直接拉取或指出问题。仍未修的三组(均已覆盖,
analyzeCommandPolicy实测)git push origin +main:destructive-git 从行正则改为按解析后的 argv 判定(与isRecursiveForceRemove同一路径),push 的判据新增+refspec操作数git -C repo reset --hard/git -c x=y push --force:新增全局选项跳过逻辑(-C/-c/--git-dir/--work-tree/--namespace/--config-env/--exec-path及 pager/pathspec 类 flag),先定位真实子命令再判定;未知或动态选项按未命中处理,不猜子命令systemctl poweroff/systemctl halt/init 0:lifecycle 集合加入halt/poweroff,init/telinit额外匹配运行级 0 和 6
反向问题(copy-device 误报)
判据改为
if=或of=之一指向/dev/:dd if=image of=out.img回到 ordinary,dd of=/dev/sda if=image(写设备)与dd if=/dev/zero of=disk.img(读设备)两个方向都仍然命中。测试:
step-command-policy.test.ts新增上述全部正例,以及必须保持 ordinary 的近似形态(git push --force-if-includes、main+topic结尾的+、git clean -xdn、echo 'git push --force'等)。command-policy/permissions 相关 6 个测试文件 511 通过;全套件仅有的 17 个失败在干净 main 上同样失败(与本改动无关)。感谢详细反馈和持续跟进!
我们已经针对高危命令识别规则进行了部分修复与优化,完善了部分 Git 强制操作、设备读写及文件截断命令的识别逻辑,相关改动可参考 PR #209。对于后续复测发现的剩余漏检及误报问题,我们也已关注到相关修复方案,将继续跟进代码审核与验证。
感谢你提供详细的复现案例和测试结果,对我们完善命令执行安全机制非常有帮助!
What happened?
The dangerous-command rules in
packages/coding-agent/src/step/command-policy.ts:93-105miss several standard, unobfuscated forms of the exact command classes they are meant to catch. Since the default permission preset isbypass("Run ordinary tools without approval; dangerous commands still ask") and an unmatched command analyzes asordinaryand is allowed with no confirmation (decideStepToolCall,permissions.ts), these execute silently in the default configuration:dd bs=4M if=disk.img of=/dev/sda/dd of=/dev/sda if=/dev/zero— thecopy-devicerule/\bdd\s+if=/iurequiresif=immediately afterdd; anybs=/of=first defeats it.git push -f origin main/git push origin +main—destructive-gitonly matches--force, not-for+refspec.git -C repo reset --hard/git -c x=y push --force— the regex requires the subcommand to immediately followgit, so any global option defeats all three git rules.systemctl poweroff/systemctl halt/init 0—DANGEROUS_LIFECYCLE_COMMANDSonly containsreboot/shutdown.:> /dev/sda—/\b:>\s*\/dev\//ucan never match realistic input:\bbefore:requires a preceding word character, so only odd forms likex:> /dev/sdamatch. The rule is effectively dead code.Steps to reproduce
Feeding each command through
analyzeCommandPolicyreturns{ kind: "ordinary" }, anddecideStepToolCall("run_command", ..., bypass)returns{ action: "allow" }— whilerm -rf ./buildandgit push --forcecorrectly returnconfirm.Expected behavior
Standard forms of these dangerous commands should trigger confirmation, as the bypass preset promises. Suggestions: match
of=/dev/anywhere in dd args; evaluate git via parsed argv (asisRecursiveForceRemovealready does) to cover-f,+refspec, andgit -C/-cprefixes; addpoweroff/haltandinit 0|6to the lifecycle set; fix or drop the:>rule; add tests using each rule’s standard spellings. Happy to implement this if you’d like.Version
main @ e411b1a