Author: Anthony Ayodeji (AyoProxy)
A critical remote code execution (RCE) risk was found in a legacy file-upload flow used by the "Proof of Ownership" feature. The implementation relied on client-supplied metadata (browser-provided MIME types and original filenames) to validate and store uploads. An attacker could spoof these values and upload executable payloads (e.g., a .php shell) disguised as images, which could then be executed on the server.
I implemented a defense-in-depth remediation that eliminates this attack vector by enforcing strict server-side validation, deterministic renaming, and cross-checking content metadata. The changes fully mitigate the risk of uploading executable files and make any bypass attempts inert.
- Root cause: The upload handler trusted client-provided MIME type and preserved original filenames and extensions when saving files.
- Attack vector: An attacker modifies the HTTP request (Content-Type and filename) to submit a malicious script disguised as an image (for example, a
.phpfile reported asimage/jpeg). If saved with an executable extension and accessible under the web root, the script could be executed. - Impact: Remote code execution, data disclosure, and full application compromise.
- Likelihood: High for any publicly reachable upload endpoint that uses client-supplied metadata for validation.
- Evidence: Legacy handler validated using
$_FILES['file']['type']and stored files using original filenames, enabling extension-based execution.
The revised upload_proof_file workflow implements three core protections:
-
Strict server-side extension allowlist
- The server ignores client MIME-type claims and validates file types by allowed extensions only.
- Allowed extensions:
jpg,jpeg,png,pdf(case-insensitive). - Any file that does not match the allowlist is rejected with a security error.
-
Deterministic server-side renaming and sanitization
- Uploaded files are not stored using the original filename.
- Files are renamed to a safe, application-controlled pattern (for example:
proof_<timestamp>_<safe_id>.<ext>), where<ext>is one of the validated static extensions. - This prevents path traversal and ensures uploaded content cannot be saved with an executable extension.
-
Deep content inspection and consistency checks
- After extension validation, the server cross-checks file content (e.g., by reading file headers or using a server-side MIME detection library) to ensure the content matches the expected type for that extension.
- If the extension and actual content disagree, the upload is rejected.
- As an additional hardening step, consider running a lightweight image parser to confirm the file is a valid image (for
jpg,png) rather than relying on header heuristics alone.
- Do not rely on client-provided
Content-Typeor$_FILES['file']['type']— treat them as untrusted input. - Use a small allowlist of known safe extensions. Avoid allowing any server-executable extensions at all.
- Use safe storage locations:
- Store user-uploaded files outside the application code directories and web root if possible.
- If files must be web-accessible, serve them through a dedicated handler that enforces content-type headers and denies script execution.
- Sanitize and validate any derived identifiers (e.g., IMEI or user IDs) used in filenames; prefer hashing or encoding rather than passing raw user-controlled strings.
- Consider additional mitigations:
- Content-disposition and strict response headers (
Content-Security-Policy,X-Content-Type-Options: nosniff) when serving uploaded files. - Virus/malware scanning for uploads.
- Size limits and rate limiting per account/IP for upload endpoints.
- Detailed audit logging for uploads (who, when, filename, checks performed).
- Content-disposition and strict response headers (
- Attack surface removed: Uploads cannot be stored with executable extensions, reducing chance of RCE via uploaded scripts.
- Defense-in-depth: Even if an attacker bypasses extension checks, the renaming step forces a safe extension; deep content checks further invalidate disguised payloads.
- Recommended tests:
- Attempt to upload files with spoofed MIME types and executable extensions — confirm rejection.
- Upload valid and corrupted image files to ensure content-inspection rejects corrupted or non-image payloads.
- Confirm stored filenames match the server-generated naming pattern and never include user-supplied extensions or directory components.
The implemented changes convert a high-risk, client-trusted upload flow into a hardened, server-controlled one. By applying an extension allowlist, deterministic renaming, and content inspection, the system is now robust against the class of RCE attacks that arise from malicious file uploads.
Contact: Need a CyberSecurity Expert, Developer and Engineeer ==> LinkedIn