Skip to content

merge-guard: is_dangerous_command under-block — python -c subprocess.run list-form evades DANGEROUS_PATTERNS substring scan #1053

Description

@michael-wojcik

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions