From de5c2da0027dbc767148e830df19c16da624f407 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 03:47:20 +0000 Subject: [PATCH] fix(extractors): refine upload_security regexes to eliminate false positives\n\n- Fix KEY_FROM_NAME flagging benign originalname template strings.\n- Fix TRUST_CLIENT_MIME flagging safe usages like logging.\n- Fix ACCEPT_SVG flagging strict rejection cases.\n- Add permanent regression tests in `test_pentest_regressions.py`. --- CHANGELOG.md | 4 ++++ .../extractors/upload_security.py | 15 ++++++++----- tests/test_pentest_regressions.py | 22 +++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db53af9..cdebd4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +### Fixed +- **Upload Security Extractor False Positives** — refined `KEY_FROM_NAME`, `TRUST_CLIENT_MIME`, and `ACCEPT_SVG` regexes to stop flagging benign usage of originalname in string templates, common mimetype logging, and explicit SVG rejection conditions. + + ### Added - **No-Row-Level-Security detection** (`missing-rls` class, in `schemas.py` + the ledger) — committed diff --git a/src/websec_validator/extractors/upload_security.py b/src/websec_validator/extractors/upload_security.py index dc0c2ba..19edc30 100644 --- a/src/websec_validator/extractors/upload_security.py +++ b/src/websec_validator/extractors/upload_security.py @@ -25,11 +25,16 @@ ALLOW_LIST = re.compile(r"isAllowedMediaType|allowedMimeTypes|allow[_-]?list|whitelist|ALLOWED_(?:MIME|TYPES|EXT)" r"|ACCEPTED_(?:MIME|TYPES?|EXT)|accepted(?:Mime|File|Content)?(?:Types?|Extensions?)" r"|\bfile-type\b|fileTypeFrom|magic[_-]?byte|detectContentType|\.fromBuffer\b|sniff", re.I) -KEY_FROM_NAME = re.compile(r"(?:Key|key|path|filename|filepath|destination|filename\s*\()\s*[:=(][^;\n]{0,90}" - r"\b(?:originalname|originalName|file\.name)\b" - r"|`[^`]*\$\{[^}]*\boriginalname\b[^}]*\}[^`]*`", re.I) -TRUST_CLIENT_MIME = re.compile(r"(?:req\.files?\.[\w$.]*\.|\bfile\.)mimetype\b|headers\[['\"]content-type['\"]\]", re.I) -ACCEPT_SVG = re.compile(r"image/svg\+xml|['\"]svg['\"]", re.I) +KEY_FROM_NAME = re.compile(r"(?:Key|key|path|filename|filepath|destination|filename\s*\()\s*[:=(]\s*" + r"(?:[^;{\n]{0,90}?)?" + r"(?:\b(?:originalname|originalName|file\.name)\b" + r"|`[^`]*\$\{[^}]*\b(?:originalname|originalName|file\.name)\b[^}]*\}[^`]*`)", re.I) +TRUST_CLIENT_MIME = re.compile(r"(?:===|!==|==|!=|\.includes\s*\(|[=:]\s*|switch\s*\(\s*|(?'); multer();" + } + ctx = repo(snippets) + + # Test originalname FP + out1 = UploadSecurityExtractor().extract(repo({"fp1.ts": snippets["fp1.ts"]}), {}) + self.assertNotIn("upload-key-from-filename", [f["kind"] for f in out1["findings"]], "Flagged benign originalname usage") + + # Test SVG FP + out_svg = UploadSecurityExtractor().extract(repo({"fp3.ts": snippets["fp3.ts"], "fp5.ts": snippets["fp5.ts"]}), {}) + self.assertNotIn("upload-accepts-svg", [f["kind"] for f in out_svg["findings"]], "Flagged benign SVG rejection/response") + + # Test MIME FP + out_mime = UploadSecurityExtractor().extract(repo({"fp4.ts": snippets["fp4.ts"]}), {}) + self.assertNotIn("upload-trusts-client-mime", [f["kind"] for f in out_mime["findings"]], "Flagged benign mimetype logging") + def test_unsafe_upload_and_serve_flagged(self): out = UploadSecurityExtractor().extract(repo({ "upload.ts": "const u=multer({}); function uploadMedia(req,res){ if(isExecutableMimeType(req.file.mimetype)) return;"