Code

Build a secure custom file upload handler

A front-end resume upload scenario covering real MIME sniffing versus extension checks, execution-proofing the uploads directory, and safe filename handling.

Works with Claude / GPT1,300 uses 4.3

The prompt

code-secure-file-upload-handler
I need a custom front-end form where job applicants upload a resume (PDF or DOCX,
max 5MB) that gets attached to a custom post type entry. This is not going through
the standard wp-admin media uploader, it's a public-facing form on a careers page.

CONTEXT: [logged-out visitors can submit this form, and a previous version of this
feature only checked the file extension, which is how a security scan flagged it as a
potential arbitrary file upload risk]

Rebuild this like a senior dev doing a security-focused rewrite, in order:
1. Explain precisely why extension-checking alone is insufficient: a file named
   `resume.pdf` can still contain executable PHP if the server is misconfigured to
   execute it, or can be a disguised file type that later processing (a PDF parser, a
   preview generator) chokes on unexpectedly. Show the correct check using
   `wp_check_filetype_and_ext()` combined with a real content sniff via PHP's `finfo`
   class, not just `pathinfo()`.
2. Enforce a strict allowlist of exactly two MIME types (`application/pdf` and
   `application/vnd.openxmlformats-officedocument.wordprocessingml.document`), reject
   anything else with a clear error, and enforce the 5MB limit server-side (not just
   via the HTML `accept` and a JS size check, which a direct POST bypasses entirely).
3. Use `wp_handle_upload()` with a custom `upload_dir` filter to store these in a
   dedicated subdirectory, and show the `.htaccess` (or Nginx equivalent) rule to
   disable PHP execution in that directory entirely, so even if a malicious file
   somehow got past validation, it can't be executed by requesting it directly.
4. Sanitize the filename with `sanitize_file_name()` and generate a randomized prefix
   to prevent path traversal attempts and to avoid collisions or information leakage
   from predictable filenames (an attacker guessing other applicants' resume URLs).
5. Require a nonce and a lightweight rate limit (e.g. a transient keyed by IP) on the
   submission endpoint itself, since this form is reachable by anyone without login,
   making it a target for automated abuse even before considering the file content.

Adjust the file types, size limit, and storage location for your actual use case.

The extension-only check in the original version is a classic mistake precisely because it looks sufficient in casual testing. Real MIME sniffing plus disabling execution in the upload directory is the combination that actually closes the gap, not either one alone.