fix(sanitizer): close exfiltration guard markdown/HTML image regex bypasses#6507
Merged
Conversation
bug-ops
enabled auto-merge (squash)
July 19, 2026 19:30
bug-ops
force-pushed
the
fix/6476-exfil-image-regex-bypass
branch
from
July 19, 2026 19:31
89c9eef to
b61752b
Compare
…passes ExfiltrationGuard::scan_output only matched a narrow literal syntax for markdown/HTML images, missing three CommonMark/HTML5-valid variants that real renderers still treat as images: leading whitespace or angle-bracket wrapping in the link destination, and unquoted HTML img src attributes. Loosen MARKDOWN_IMAGE_RE, REFERENCE_DEF_RE, and HTML_IMG_RE to cover all three, threading the correct alternate capture group through at every call site, and add regression tests for each variant. Also fixes a regression introduced while tightening the bare-URL match: narrowing it to stop before a whitespace-wrapped destination broke detection of standard CommonMark image titles, closed by adding an explicit optional title clause to the regex. Closes #6476
bug-ops
force-pushed
the
fix/6476-exfil-image-regex-bypass
branch
from
July 19, 2026 19:34
b61752b to
2c161dc
Compare
7 tasks
bug-ops
added a commit
that referenced
this pull request
Jul 19, 2026
… bypasses in exfiltration guard ExfiltrationGuard::scan_output's image-URL detection anchored on a literal lowercase https?:// scheme and required an explicit scheme, so uppercase/ mixed-case schemes (HTTPS://evil.com/...) and scheme-relative destinations (//evil.com/...) - both valid and renderer-equivalent to https:// - bypassed detection silently. A backslash-escaped quote in a CommonMark image title also broke the title regex added in #6507. Make scheme matching case-insensitive across all three detection regexes and is_external_url, and treat an optional scheme-relative // prefix as equivalent to an explicit https?://. Tolerate \" as a non-terminating escaped quote in the double-quoted title branch. Fold in the same casing fix for the sibling URL_EXTRACT_RE (tool-URL-injection flagging path); scheme-relative support there is deferred as a larger design change (exact-string flagged-URL-set semantics), marked with a TODO comment. Closes #6508
bug-ops
added a commit
that referenced
this pull request
Jul 19, 2026
… bypasses in exfiltration guard (#6518) * fix(sanitizer): close case-insensitive scheme and scheme-relative URL bypasses in exfiltration guard ExfiltrationGuard::scan_output's image-URL detection anchored on a literal lowercase https?:// scheme and required an explicit scheme, so uppercase/ mixed-case schemes (HTTPS://evil.com/...) and scheme-relative destinations (//evil.com/...) - both valid and renderer-equivalent to https:// - bypassed detection silently. A backslash-escaped quote in a CommonMark image title also broke the title regex added in #6507. Make scheme matching case-insensitive across all three detection regexes and is_external_url, and treat an optional scheme-relative // prefix as equivalent to an explicit https?://. Tolerate \" as a non-terminating escaped quote in the double-quoted title branch. Fold in the same casing fix for the sibling URL_EXTRACT_RE (tool-URL-injection flagging path); scheme-relative support there is deferred as a larger design change (exact-string flagged-URL-set semantics), marked with a TODO comment. Closes #6508 * docs(sanitizer): link URL_EXTRACT_RE TODO to filed follow-up issue #6519
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ExfiltrationGuard::scan_output's markdown/HTML image detection regexes only matched a narrow literal syntax, missing three CommonMark/HTML5-valid variants real renderers still treat as images: leading whitespace or angle-bracket-wrapped link destinations, and unquoted HTML<img src=...>attribute values.MARKDOWN_IMAGE_RE,REFERENCE_DEF_RE, andHTML_IMG_REto cover all three variants via regex alternation, updating capture-group consumption at every call site inscan_output.). Fixed by adding an explicit optional title clause (double-quoted, single-quoted, or paren-wrapped).scan_output()actually blocks/substitutes each bypass variant (not just that the regex matches), covering the three original bypasses, the title-syntax fix, and combinations of the two.Two minor, pre-existing gaps outside this PR's scope were flagged during review as follow-up candidates: case-sensitive scheme matching (
HTTPS://bypasses both the regex andis_external_url) and scheme-relative URLs (//evil.com/x.gifbypasses allhttps?://-anchored patterns). Will file a separate issue for these.Closes #6476
Test plan
cargo nextest run -p zeph-sanitizer— 366 passed, 2 skippedcargo +nightly fmt --check— cleancargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings— cleancargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins— 14644 passed, 35 skippedRUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --workspace --features "desktop,ide,server,chat,pdf,scheduler"— cleangitleaks protect --staged --no-banner --redact— no leaks