Skip to content

merge-guard: curl/wget git/refs + branches/protection mint uses first-match extraction (no count, no metachar refusal) → cross-target/glob laundering (v4.4.54) #1109

Description

@michael-wojcik

Class

Security / under-block (laundering). Tolerated direction per the ratified merge-guard asymmetry (defense-in-depth-backed, shipped no known incident) — NOT the cardinal over-block direction, so it did not gate #1098. Same target-confusion class #1096 closed for curl/wget merges via the per-leg endpoint helper; git/refs and branches/protection never received that treatment.

Confirmed empirically (real code, v4.4.54)

The existing curl/wget git/refs (and by inspection branches/protection) mint uses whole-command first-match target extraction with no multi-endpoint count and no metachar/encoding refusal:

  • curl -X DELETE https://api.github.com/repos/o/r/git/refs/heads/main https://api.github.com/repos/o/r/git/refs/heads/dev → detect=branch-delete, binds branch='main', silently ignores dev. Approve "delete main" → curl DELETEs both refs. (Cross-target launder: approve one, delete two.)
  • curl -X DELETE https://api.github.com/repos/o/r/git/refs/heads/{main,dev} → binds branch='heads/' (the glob { broke the extractor regex). Approve nonsense → curl globs + deletes main AND dev. (Mis-bind launder.)

Disposition (updated 2026-07-05): standalone — the #1098 unified cure is WON'T-FIX

Superseded plan (do not act on): this was previously slated to be closed as part of the #1098 unified cure (Design D+). That cure is now WON'T-FIX — an 8-round dual/triple-independent investigation proved a by-construction-sound curl/wget destructive-endpoint extractor is structurally impossible (it must parse an unbounded, version-growing curl value-flag vocabulary; the fail-open relocates across axes and hits the wall in both the launder and over-block directions — see the #1098 close record). So this residual is NOT closed by that cure.

Current disposition: #1109 stands as a standalone tolerated under-block residual on the git/refs + branches/protection curl/wget mint arms (defense-in-depth-backed; no known incident; the read floor still gates these commands so they route through the user's approval click). It is the same first-match target-confusion class, un-cured for these two endpoints.

Constraint on any future fix: it must be curl/wget-narrow and cannot rely on a general sound extractor (the #1098 wall applies identically to git/refs/protection first-match extraction). Options are (a) a bounded, endpoint-specific narrowing that provably never over-blocks a faithful single, or (b) explicit acceptance as a permanent tolerated residual. The gh-api arm remains soundly gated and is unaffected.

Certification (required before any narrow future closure)

Bidirectional sweep over the full curl/wget destructive-endpoint corpus:

  • No-new-over-block (cardinal direction, PRIMARY): no faithful single-target destructive click is blocked.
  • No-launder: every multi-target / glob / --next cross-op / metachar/encoding shape either declines or binds exactly the requested set (never a superset, never a wrong single).

Closure is gated on a fresh dual-independent adversarial pass + the SACROSANCT post-install live-probe — do not auto-close on PR merge.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    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