Skip to content

VNX-178: Improper Handling of Case Sensitivity

Reports an uploaded file's name or extension compared case-sensitively against a dangerous extension (php, jsp, aspx, exe, sh, html, svg, htaccess...), a deny check that "shell.PHP" bypasses.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-178
Severity Low
SARIF level note
Kind sast
Languages Go, Java, JavaScript / TypeScript, Python, PHP
CWE CWE-178
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:L/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L
Tags case-sensitivity validation file-upload cwe-178
Source internal/sast/rules/vnx-178.rego

Overview

VNX-178 maps to CWE-178: Improper Handling of Case Sensitivity. It reports a case-sensitive comparison of a file name or extension against a dangerous extension (php/phtml/phar, jsp/jspx, asp/aspx, exe/dll, sh/bat/cmd/ps1, cgi/pl/py/rb, js, html/svg, htaccess, war/jar) in a Python, JavaScript/TypeScript, Java, Go or PHP file that handles uploads (request.files, multer originalname, MultipartFile, FormFile, $_FILES). The comparison forms are endswith/endsWith/HasSuffix/str_ends_with, ==/===/!=, equals, membership (in [...], in_array, includes, contains), membership in a deny-list collection of those extensions defined in the same file (ext in BLOCKED_EXTENSIONS, in_array($ext, $blocked)), and a case-sensitive regular expression (/\.(php|jsp)$/.test(name) without the i flag, re.search(r"\.(php|exe)$", name) without re.I, Java matches without (?i)). The line must name the value as a file name, extension, suffix or path.

Not reported: a format, language or output parameter compared with "html" or "py"; a value lower- or upper-cased on the same line, or assigned from lower()/toLowerCase()/strings.ToLower/strtolower/casefold in the ten lines above; equalsIgnoreCase/EqualFold; allow-lists of harmless extensions; files that do not handle uploads; the comparison inside a string literal; comments. A case-sensitive comparison against a role name such as "admin" fails closed and is not reported.

Why This Matters

Web servers and interpreters usually match extensions without regard to case, or run on case-insensitive file systems. A filter that rejects .php but accepts .PHP or .pHp lets an attacker upload a script the server will still execute.

What Gets Flagged

# FLAGGED
if filename.endswith((".php", ".exe", ".sh")):
    abort(400)
// FLAGGED
const ext = path.extname(file.originalname);
if (ext === '.php' || ext === ".jsp") { ... }
// FLAGGED
if strings.HasSuffix(header.Filename, ".php") { ... }
// FLAGGED: no i flag
if (/\.(php|jsp|exe|sh)$/.test(file.originalname)) { ... }
# NOT FLAGGED: normalised first
ext = os.path.splitext(f.filename)[1].lower()
if ext in [".php", ".phtml"]:
    abort(400)

Remediation

  1. Lower-case the file name or extension before any comparison.
  2. Prefer an allow-list of the extensions you accept to a deny-list of the ones you fear.
  3. Store uploads outside the web root under a generated name, so the uploaded name never decides how the file is served.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-178
// nosec vnx-178

Or record an ignore rule: vulnetix ignore add --rule vnx-178 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-178.rego, cli/internal/sast/docs/vnx-178.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.