Skip to content

merge-guard: 2 more pre-existing detection under-blocks (quote-unaware comment strip + bash-5.3 funsub) #1056

Description

@michael-wojcik

Two more pre-existing detection-layer under-blocks (surfaced by the #1037 blind review)

Both are PRE-EXISTING in the shipped merge_guard (verified is_dangerous_command = False on main, independent of any #1037 suppressor work). Same broad class as #1053 / #1055 — the detection layer (strip steps + substring scan) does not model bash's command boundaries / execution contexts.

A — quote-unaware comment strip (boundary-hiding)

Step-2's comment strip (regex (?:^|(?<=\s)|(?<=;))#.*$) is not quote-aware: a space-preceded # inside a quoted argument makes it delete the closing quote + a real ;/&& separator + the trailing destructive op, before the dangerous-pattern scan runs.

echo "a # b" ; gh pr merge 5 --admin              ->  is_dangerous = False  (UNDER-BLOCK)
git commit -m "fix # done" && git push --force origin main   ->  is_dangerous = False  (UNDER-BLOCK)

Shell-universal, verb-independent, same-line. Introduced ~2026-03-10 (commit 59b5be6a). Plausible for an honest operator (a commit message containing a #, then a push) — arguably the most reachable of this class.

B — bash 5.3 funsub ${ cmd; } inside double quotes

_has_command_substitution only checks for $( / backtick, so a double-quoted ${ … ; } (bash ≥ 5.3 function-substitution) is treated as inert and blanked by carrier strips, though bash executes it.

echo "${ gh pr merge 5; }"   ->  is_dangerous = False   (consumer-shell-gated: bash >= 5.3)

Scope / priority

Both bounded by the authored-text threat model (the guard protects an honest operator from accidental/unapproved destructive ops, not an adversary obfuscating their own command). Low–medium priority. A sound fix is part of the same "real bash parser" direction as #1037's deferred general fix.

Siblings: #1053 (subprocess.run list-form), #1055 (python var-laundering), #1037 (over-block, general fix deferred).

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