wrapper-guard: the percent-escape refusal reads the whole command, so a format specifier in an unrelated argument blocks a literally-spelled endpoint #1230

Open
opened 2026-08-15 21:25:08 +00:00 by Ghost · 0 comments

What happens

wrapper-guard.sh refuses a provider API write whose command text contains a percent-escape,
so that an encoded path segment cannot slip past the literal endpoint map. The reasoning is sound
and the comment above it is one of the better-argued passages in the file.

The test itself is applied to the whole command:

if printf '%s' "$CMD" | grep -Eq '%[0-9A-Fa-f][0-9A-Fa-f]'; then

$CMD is the entire tool invocation, not the request target. So any other argument in the same
compound command that happens to contain a percent followed by two hex characters refuses a call
whose endpoint is spelled perfectly literally.

Git's own format specifiers are the common case, because both letters are hex digits:

Spelling Reads as Where it appears
%ae %AE git log --format=%ae
%ad %AD git log --format=%ad
%cd, %ce %CD, %CE committer date/email
%db %DB date +%db-style formats, printf '%db'

Anything else that formats will do it too — printf '%02d', a date +... with a hex-lettered
specifier, a sed expression carrying a literal percent.

Why it matters more than a nuisance

The two halves of the guard interact badly. A caller reaching a genuinely unwrapped endpoint has
to use the raw API, which is allowed; if that same command also formats some git output for the
same report, the guard refuses it, and the ONLY documented way forward is the break-glass
MOSAIC_WRAPPER_OVERRIDE=1. A guard that pushes a correct call toward its own override is
training the exact habit it exists to prevent, and the block message says nothing about the real
cause — the operator reads "provider API WRITE containing a percent-escape", looks at an endpoint
with no escape in it, and concludes the guard is broken.

Suggested direction

Test the request target rather than the command. The file already isolates endpoints for the map
below this branch, so the machinery exists.

The honest caveat, which is why this is a direction and not a patch: a URL assembled from a
variable cannot be isolated, and narrowing the test to a literal URL operand would clear those.
Suggest testing the URL operand when one can be isolated and keeping the whole-command test as the
fallback when none can — that preserves the refusal exactly where the hazard is unreadable and
drops it where the endpoint is plainly literal.

Reproduce

Any command that is classified as an API write and also carries --format=%ae in an unrelated
segment. Expected: allowed (the endpoint is literal). Actual: exit 2 with the percent-escape block.

Related but distinct: the block-message routing issue, and the checkout-target issue — this one is
about which string the escape test reads.

## What happens `wrapper-guard.sh` refuses a provider API **write** whose command text contains a percent-escape, so that an encoded path segment cannot slip past the literal endpoint map. The reasoning is sound and the comment above it is one of the better-argued passages in the file. The test itself is applied to the whole command: ``` if printf '%s' "$CMD" | grep -Eq '%[0-9A-Fa-f][0-9A-Fa-f]'; then ``` `$CMD` is the entire tool invocation, not the request target. So any *other* argument in the same compound command that happens to contain a percent followed by two hex characters refuses a call whose endpoint is spelled perfectly literally. Git's own format specifiers are the common case, because both letters are hex digits: | Spelling | Reads as | Where it appears | |---|---|---| | `%ae` | `%AE` | `git log --format=%ae` | | `%ad` | `%AD` | `git log --format=%ad` | | `%cd`, `%ce` | `%CD`, `%CE` | committer date/email | | `%db` | `%DB` | `date +%db`-style formats, `printf '%db'` | Anything else that formats will do it too — `printf '%02d'`, a `date +...` with a hex-lettered specifier, a `sed` expression carrying a literal percent. ## Why it matters more than a nuisance The two halves of the guard interact badly. A caller reaching a genuinely unwrapped endpoint has to use the raw API, which is allowed; if that same command also formats some git output for the same report, the guard refuses it, and the ONLY documented way forward is the break-glass `MOSAIC_WRAPPER_OVERRIDE=1`. A guard that pushes a correct call toward its own override is training the exact habit it exists to prevent, and the block message says nothing about the real cause — the operator reads "provider API WRITE containing a percent-escape", looks at an endpoint with no escape in it, and concludes the guard is broken. ## Suggested direction Test the request target rather than the command. The file already isolates endpoints for the map below this branch, so the machinery exists. The honest caveat, which is why this is a direction and not a patch: a URL assembled from a variable cannot be isolated, and narrowing the test to a literal URL operand would clear those. Suggest testing the URL operand when one can be isolated and keeping the whole-command test as the fallback when none can — that preserves the refusal exactly where the hazard is unreadable and drops it where the endpoint is plainly literal. ## Reproduce Any command that is classified as an API write and also carries `--format=%ae` in an unrelated segment. Expected: allowed (the endpoint is literal). Actual: exit 2 with the percent-escape block. Related but distinct: the block-message routing issue, and the checkout-target issue — this one is about *which string* the escape test reads.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1230