Skip to content

fix(testing): match shell echoes the shell actually produces - #2320

Merged
chaliy merged 1 commit into
mainfrom
claude/pensive-hypatia-92oe7p
Aug 21, 2026
Merged

chaliy merged 1 commit into
mainfrom
claude/pensive-hypatia-92oe7p

Conversation

@chaliy

@chaliy chaliy commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

What changed

The fuzz leak detector now recognizes a shell echo of user input regardless of how the shell transformed that input, and regardless of whether the diagnostic fits on one line. Test-harness and fuzz-target only — no shell behavior changes.

Why

glob_fuzz went red again on main (run 219, input \n \0{ code:<(])\n) — the second failure of this class in two days:

[glob_fuzz] stderr leaks banned shape ` { code:` (after stripping shell echoes):
---raw stderr---
bash: { code:<(])
: command not found

#2319 fixed one diagnostic's wording. That was necessary but treated a symptom. Run 219 exposed the two harness gaps underneath both failures:

1. The pre-filter checked raw bytes; the shell transforms them. glob_fuzz skips inputs containing a UNIVERSAL_BANNED shape, but NUL is dropped during word expansion — so \0{ code: and </r\0ustc/ slip past a literal contains and reappear in stderr as { code: and /rustc/. Both crashes hinge on exactly this. Targets now call input_echo_would_trip, which checks the input as the shell will render it back.

2. The echo filter was line-based; the input slot can contain newlines. The command name here ends in \n, so bash's one-line bash: %s: command not found template renders across two lines and neither half matched. Matching is now span-based: an unclosed bash: / ls: cannot access line extends to the first later line ending in a template suffix.

Quote and backslash removal can synthesize banned shapes the same way NUL stripping does. That's why the detector no longer leans on the pre-filter alone — the two are independent defenses, and fixing only the pre-filter would leave the same class open.

Before / After

Both crash inputs replayed through the real fuzz target, rebuilt on this branch:

$ cargo +nightly fuzz run glob_fuzz fuzz/artifacts/glob_fuzz/crash-2ac9af1dcb0bb66e7849b347828a8236e12fdda3
Executed crash-2ac9af1dcb0bb66e7849b347828a8236e12fdda3 in 1 ms
$ cargo +nightly fuzz run glob_fuzz fuzz/artifacts/glob_fuzz/crash-fae53719665e9c77d2e1a1b7d4da7e43902525d0
Executed crash-fae53719665e9c77d2e1a1b7d4da7e43902525d0 in 0 ms

On main, the first of those aborts with libFuzzer: deadly signal.

Risk

  • Low — no library code changes; src/testing.rs is #[doc(hidden)] test-only.

Span matching widens what gets stripped, so the guard is that it strips as little as possible: the span closes on the earliest candidate line, so a leak printed after a complete diagnostic survives (strip_span_stops_at_the_first_closing_line), and an unclosed bash: line swallows nothing (strip_keeps_unclosed_bash_prefix_span). A leak cannot be swallowed inside a span, because each shell diagnostic is formatted and written as one string with nothing interleaved.

The pre-existing strip_keeps_* tests — which exist precisely to catch over-stripping — all still pass unmodified.

Verified: 16/16 testing:: unit tests, 6/6 glob_fuzz scaffold tests, workspace lib/bins/tests, doc tests, realfs, failpoints, proptest_security, clippy -D warnings, cargo fmt, check_okf.py, check_doc_links.py, plus a long glob_fuzz session against the rebuilt target (CI reached its failure at ~121k executions).

ssh_supabase_connects fails locally (sandbox blocks outbound port 22) — environmental, green on main in CI.

Checklist

  • Tests added or updated
  • Backward compatibility considered

Generated by Claude Code

`glob_fuzz` run 219 went red on `\n \0{ code:<(])\n`, the second failure
of this class in two days. Run 218's fix corrected one diagnostic's
wording; this corrects the two harness gaps underneath both.

The pre-filter checked the raw input bytes, but the shell transforms them
before echoing: NUL is dropped during word expansion, so `\0{ code:` and
`</r\0ustc/` slip past a literal `contains` and reappear in stderr as
` { code:` and `/rustc/`. Targets now call `input_echo_would_trip`, which
checks the input as the shell will render it back.

The echo filter was line-based, but the user-input slot can contain
newlines: a command name ending in `\n` renders bash's one-line
`command not found` template across two lines, and neither half matched.
Matching is now span-based — an unclosed `bash: `/`ls: cannot access `
line extends to the first later line ending in a template suffix.

Closing on the earliest candidate keeps the span minimal, so a leak
printed after a complete diagnostic still survives; and a leak cannot be
swallowed inside a span, because each shell diagnostic is formatted and
written as one string with nothing interleaved. The pre-existing
`strip_keeps_*` tests pin that direction and still pass.

Quote and backslash removal can synthesize banned shapes the same way
NUL stripping does, which is why the detector no longer depends on the
pre-filter alone — the two are independent defenses.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bashkit 39400b5 Commit Preview URL

Branch Preview URL
Aug 21 2026, 10:53 AM

@chaliy
chaliy merged commit 0da2286 into main Aug 21, 2026
42 checks passed
@chaliy
chaliy deleted the claude/pensive-hypatia-92oe7p branch August 21, 2026 11:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant