UploadClientMimeTrusted
warning native on by defaultGroup: Security
Detect acceptance of an upload based solely on $_FILES entry type compared to an allowed MIME string without server-side content inspection.
Example
php
<?php
if ($_FILES['file']['type'] === 'image/png') { move_uploaded_file($_FILES['file']['tmp_name'], '/srv/uploads/image.png'); }
function storeAvatar() {
if (!in_array($_FILES['avatar']['type'], ['image/png', 'image/jpeg'], true)) { return; }
move_uploaded_file($_FILES['avatar']['tmp_name'], '/srv/avatars/new');
}
function storeScan() {
if ($_FILES['scan']['type'] !== 'image/png') { return; }
if (getimagesize($_FILES['scan']['tmp_name']) === false) { return; } // content inspected: no report
move_uploaded_file($_FILES['scan']['tmp_name'], '/srv/scans/new');
}Reported:
- line 2: Inspect uploaded content instead of trusting its client MIME label.
- line 5: Inspect uploaded content instead of trusting its client MIME label.
Detection
- Report a builtin
move_uploaded_file()call whose source is$_FILES[key]['tmp_name'](literal key) when the call is reached only if the client-supplied$_FILES[key]['type']of the same entry matched an allowed MIME string, and no server-side content inspection of that temporary file is found (E1). - A client type test is
$_FILES[key]['type'](a literal key, or a local holding one that stays unchanged, as does every$_FILESelement, up to the call) compared (==,===,!=,!==, either operand order) with a string literal, or a builtinin_array()call (positional or named arguments) whose needle is that entry type and whose haystack is a non-empty literal array of string literals, searched strictly or, when no value reads as a number, loosely. - The call is reached only if the type matched: the conditions guarding it limit the entry type to string literals that all contain
/. Tests combine through!, parentheses,&&/andand||/or(each side of a disjunction must limit it), and guard the call from the branch of anif/elseif/elsechain, a ternary ormatch (true)arm, the right operand of&&/||, or code after anifwhose branch for another type always leaves (return, throw, exit, break, continue), with or without other arms. - A call of the project between the test and the call, which may write
$_FILES, a jump label between them, a write to the entry, or a test of another entry proves nothing. - Resolve builtin calls and named arguments before checking the contract. Project-local callees are considered only when their bodies or immutable summaries establish the required facts. The default is enabled, with positive proof required.
- For flow-dependent conditions, require a reachable source-to-use path with no intervening invalidation. Unknown calls, ambiguous aliases, recursion or analysis-budget exhaustion cannot establish definite facts.
Exceptions (no report)
- E1. Server-side content inspection: anywhere earlier in the same function (or script) the same temporary file, written as
$_FILES[key]['tmp_name']or as a local variable assigned from it, is an argument of builtinfinfo_file(),mime_content_type(),getimagesize(),exif_imagetype(), animagecreatefrom*()decoder, or a method call namedfile(finfo::file(); the receiver type need not be proven). The inspection does not have to dominate the move: an acceptance path that may depend on stored bytes is not provably label-only. - Client MIME used only for display, logging or choosing a name; a test that rejects the allowed type; a guard that does not leave; a
||alternative in an accepting branch or a&&in a guard (the test is then not required); a different$_FILESentry; and upload-error or size checks alone are not client type tests. - Unresolved targets, incomplete required facts, suppressed findings and PHP versions lacking the referenced API or language feature produce no report. User declarations shadowing builtin names are not builtin contracts.
Fix
No automatic fix: content types, file size limits and image decoding policy must be selected by the application.
PHP versions
Apply only on PHP versions supporting the referenced APIs and syntax (within PHP 5.3–8.5). Builtin behavior and argument contracts follow the configured PHP version. Extension-specific calls require resolved extension API symbols; do not treat same-named application functions as extension calls.
Options
None. Enable or disable this rule through normal rule configuration.
Configure
In custos.json:
json
{
"rules": {
"UploadClientMimeTrusted": {
"enabled": false
}
}
}Suppress
Before the statement or declaration (or the first statement of the file):
php
// @custos-ignore UploadClientMimeTrusted