Problem
merge_guard_pre.py's is_dangerous_command detection is a regex substring scan over the command string (DANGEROUS_PATTERNS + .search()). A real destructive op invoked via the Python subprocess.run list form is NOT detected, because the list splits the op across elements and there is no contiguous gh pr merge substring to match:
python3 -c "import subprocess; subprocess.run(['gh','pr','merge','5'])"
→ is_dangerous_command = False (under-block: a real merge escapes detection).
By contrast the string / os.system form IS caught (contiguous literal):
python3 -c "import os; os.system('gh pr merge 5')" # → blocked (correct)
Class / scope
PRE-EXISTING limitation of the same obfuscation-evasion class already acknowledged in-code (the GraphQL/alias gaps near merge_guard_pre.py ~L183-185) and related to the >32-flag-token residual (#1001). The substring scan models contiguous command literals, not arbitrary programmatic reconstruction of the op tokens.
Threat-model note: the guard's threat model is honestly-authored command text by a trusted operator (preventing accidental/unapproved destructive ops), not an adversary deliberately reconstructing the op. The list-form is an unusual way to invoke a merge → low–medium priority.
Provenance
Surfaced during the #1037 over-block-suppressor work and independently confirmed by an adversarial re-probe; explicitly kept OUT of #1037 scope (which is an over-block correction, not a detection-coverage expansion). The #1037 suppressor does NOT introduce or affect this gap.
Possible direction (for discussion)
Detection-coverage expansion for programmatic op reconstruction (list-form, alias, GraphQL) is a larger change to the detection model — likely a coordinated effort across the known-gap class rather than a one-off. Must preserve INV-D2 (over-block acceptable, under-block never) and not regress the #1042/#1031/#1032 binding.
Problem
merge_guard_pre.py'sis_dangerous_commanddetection is a regex substring scan over the command string (DANGEROUS_PATTERNS+.search()). A real destructive op invoked via the Pythonsubprocess.runlist form is NOT detected, because the list splits the op across elements and there is no contiguousgh pr mergesubstring to match:→
is_dangerous_command= False (under-block: a real merge escapes detection).By contrast the string /
os.systemform IS caught (contiguous literal):Class / scope
PRE-EXISTING limitation of the same obfuscation-evasion class already acknowledged in-code (the GraphQL/alias gaps near
merge_guard_pre.py~L183-185) and related to the>32-flag-tokenresidual (#1001). The substring scan models contiguous command literals, not arbitrary programmatic reconstruction of the op tokens.Threat-model note: the guard's threat model is honestly-authored command text by a trusted operator (preventing accidental/unapproved destructive ops), not an adversary deliberately reconstructing the op. The list-form is an unusual way to invoke a merge → low–medium priority.
Provenance
Surfaced during the #1037 over-block-suppressor work and independently confirmed by an adversarial re-probe; explicitly kept OUT of #1037 scope (which is an over-block correction, not a detection-coverage expansion). The #1037 suppressor does NOT introduce or affect this gap.
Possible direction (for discussion)
Detection-coverage expansion for programmatic op reconstruction (list-form, alias, GraphQL) is a larger change to the detection model — likely a coordinated effort across the known-gap class rather than a one-off. Must preserve INV-D2 (over-block acceptable, under-block never) and not regress the #1042/#1031/#1032 binding.