File API — FileReader & File Input
debt(d7/e3/b3/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate automated detection is 'no' and the tool listed is semgrep, which requires a custom rule pattern to catch 'File.type used for security validation without server-side re-validation.' This is a specialist/custom pattern, not a default lint rule, and the misuse (trusting client-side MIME) is silent in production until an attacker exploits it — but a careful code reviewer could spot it, placing it at d7 rather than d9.
Closest to 'simple parameterised fix' (e3). The quick_fix specifies two concrete changes: swap FileReader for URL.createObjectURL() for image previews (one-call swap) and add finfo_file() server-side validation. This touches the JS client code and the PHP upload handler — two files but a straightforward, localised pattern replacement rather than a broad refactor.
Closest to 'localised tax' (b3). The applies_to scope is web contexts only and the concern is scoped to file upload handling logic. The misconception creates a security gap but it doesn't structurally infect unrelated parts of the codebase — only the upload component and its PHP counterpart pay the tax.
Closest to 'serious trap' (t7). The misconception field is explicit: File.type appears to validate MIME type but actually reads the browser's guess based on file extension, which is easily spoofed. A competent developer familiar with server-side MIME validation would reasonably trust File.type as analogous — but it contradicts expectations by being purely extension-based, making security-critical reliance on it a serious and non-obvious mistake.
Also Known As
TL;DR
Explanation
input[type=file].files returns a FileList of File objects (extends Blob). FileReader.readAsDataURL() for image preview; readAsArrayBuffer() for binary processing; readAsText() for CSV/text. File.size, File.type, File.name for client-side validation before sending to PHP. Drag-and-drop: DataTransfer.files. Large files: split into chunks with File.slice() and upload sequentially via fetch to PHP. PHP receives the same $_FILES as a normal form upload.
Common Misconception
Why It Matters
Common Mistakes
- Trusting File.type for security — it's based on extension, spoofable
- Not checking file size before upload to avoid wasted bandwidth
- Using FileReader for images when URL.createObjectURL() is more efficient
Code Examples
// FileReader for preview — inefficient, and trusts File.type:
if (file.type !== 'image/jpeg') throw new Error('Not a JPEG'); // spoofable
const reader = new FileReader();
reader.readAsDataURL(file); // loads entire file into memory
// Size validation client-side:
if (file.size > 10 * 1024 * 1024) throw new Error('File too large (max 10MB)');
// Efficient preview with object URL (no FileReader needed):
const preview = document.querySelector('#preview');
preview.src = URL.createObjectURL(file);
preview.onload = () => URL.revokeObjectURL(preview.src); // free memory
// PHP must re-validate:
// $finfo = new finfo(FILEINFO_MIME_TYPE);
// $mime = $finfo->file($_FILES['photo']['tmp_name']);