fix(media): tighten sanitizeMimeType anchoring#73229
Conversation
Greptile SummaryThis PR replaces the permissive Confidence Score: 5/5Safe to merge — the regex tightening is logically correct and well-tested. No P0 or P1 issues found. The new regex correctly structures parameter matching, the $ anchor behavior is properly handled by upstream .trim(), quoted-string CR/LF exclusion is explicit, and the test additions cover the new branches. No regressions are apparent in the CHANGELOG entry or test file. No files require special attention. Reviews (1): Last reviewed commit: "fix(media): tighten sanitizeMimeType anc..." | Re-trigger Greptile |
|
ProjectClownfish pushed a narrow repair to this branch so the original contributor path can stay canonical. Source PR: #73229 |
0bab8c0 to
f3db162
Compare
|
ProjectClownfish pushed a narrow repair to this branch so the original contributor path can stay canonical. Source PR: #73229 |
f3db162 to
a64ebe0
Compare
🔒 Aisle Security AnalysisWe found 2 potential security issue(s) in this PR:
1. 🟡 CR/LF allowed in MIME quoted-string parameters via regex escape range
DescriptionThe MIME type validation regex in
Even though Vulnerable code: const HTTP_QUOTED_STRING = String.raw`"(?:[\t !#-\[\]-~]|\\[\t -~])*"`;RecommendationReject CR/LF anywhere in the input, including within quoted strings. Option A (tighten the escape character class): do not use a range starting at For example, only allow HTAB/space or visible ASCII after a backslash: const QDTEXT = String.raw`[\t !#-\[\]-~]`; // no CR/LF
const QUOTED_PAIR = String.raw`\\(?:[\t ]|[!-~])`; // no CR/LF
const HTTP_QUOTED_STRING = String.raw`"(?:${QDTEXT}|${QUOTED_PAIR})*"`;Option B (defense-in-depth): explicitly reject any if (/[\r\n]/.test(trimmed)) return undefined;Add tests to ensure inputs containing 2. 🟡 Unicode case-folding bypass in MIME type sanitizer due to `/i` regex
Description
Vulnerable code: const MIME_TYPE_WITH_OPTIONAL_PARAMS = new RegExp(
String.raw`^${MIME_TYPE}(?:${MIME_PARAMETER})*$`,
"i",
);
...
const match = trimmed.match(MIME_TYPE_WITH_OPTIONAL_PARAMS);
return match?.[1]?.toLowerCase();Impact depends on downstream usage (e.g., allowlists/branching logic based on the sanitized MIME type): a crafted non-ASCII value can pass sanitization and be normalized to an ASCII token that may be treated as trusted. RecommendationAvoid Unicode case-folding during validation and explicitly enforce ASCII:
Example fix: const ASCII_ONLY = /^[\x00-\x7F]+$/;
export function sanitizeMimeType(value?: string): string | undefined {
const trimmed = normalizeOptionalString(value);
if (!trimmed || !ASCII_ONLY.test(trimmed)) return undefined;
const lower = trimmed.toLowerCase();
const match = lower.match(MIME_TYPE_WITH_OPTIONAL_PARAMS_CASE_SENSITIVE);
return match?.[1];
}
const MIME_TYPE_WITH_OPTIONAL_PARAMS_CASE_SENSITIVE = new RegExp(
String.raw`^${MIME_TYPE}(?:${MIME_PARAMETER})*$`
);This ensures only ASCII input is accepted and prevents Unicode confusable/case-folding bypasses. Analyzed PR: #73229 at commit Last updated on: 2026-04-28T04:45:40Z |
* fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring
* fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring
* fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring
* fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring
* fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring
* fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring * fix(media): tighten sanitizeMimeType anchoring
Summary
sanitizeMimeTypeend-anchored while rejecting newline-before-parameter edge cases noted by Greptile.Credit
Based on source PR #68225 by @ymaxgit / bluesky6868, with related review context from #61016 and #68456.
Validation
pnpm check:changed/reviewclean before mergeCloses #9795 when landed.
ProjectClownfish replacement details:
fatal: unable to access 'https://github.com/security-for-agent/openclaw.git/': The requested URL returned error: 403