File Upload
A complete guide to understanding, detecting, exploiting, and preventing File Upload vulnerabilities.
Introduction
File Upload Vulnerabilities
The Complete ANAS EDUCATION Course (Beginner Edition)
1. Introduction
Imagine you open your PC and visit `anastech.com`.
You log in. You go to your profile settings. You see a button that says "Change Profile Picture". You click it.
The browser opens a file picker on your computer. You choose a photo of your cat called `cat.jpg`. You click "Save".
In the next half-second, four things happen, very fast:
- ●Your browser reads the bytes of `cat.jpg` from your hard drive.
- ●Your browser packs the bytes into an HTTP request with a special envelope called `multipart/form-data`.
- ●Your browser sends that request to a URL on the server, for example `https://anastech.com/upload`.
- ●The server receives the bytes and writes them somewhere on its own hard drive, for example `/var/www/html/uploads/cat.jpg`.
If you then reload your profile page, the browser asks for `https://anastech.com/uploads/cat.jpg`. The server reads the file off disk and sends the bytes back. The browser shows the image. You see your cat. Everyone is happy.
Now look at the same picture again, but with a question on top of it:
- ●What if the file you sent was not `cat.jpg`?
- ●What if it was a tiny text file called `shell.php`?
- ●What if the inside of that file was twelve bytes that say: `<?php system($_GET['c']); ?>`?
If the server still saves the file in the same place, and the server happens to run PHP, then anyone who visits:
is not asking for a picture anymore. They are running a command on the server.
That is the file upload vulnerability. It is what happens when a feature that was supposed to accept pictures accepts code instead, and when the server treats the code as code.
This course teaches that idea slowly and completely. By the end you will know:
- ●How a normal file upload works step by step.
- ●Where the danger lives.
- ●How attackers find the danger.
- ●How defenders close the door.
You do not need to be an expert. You just need to read carefully.
2. How It Works
To find the bug, you first need to understand the normal feature in detail. Walk through it with us.
Step 1. You pick a file in the browser
When you click "Change Profile Picture" on `anastech.com`, the page contains HTML that looks like this:
Three things matter on this form:
- ●`action="/upload"` ==> the URL the browser will send the file to.
- ●`method="POST"` ==> the HTTP method.
- ●`enctype="multipart/form-data"` ==> the special envelope that carries binary files.
The `<input type="file">` opens the file picker on your computer when you click it. The `name="avatar"` is the label the server will use to find the file inside the request body.
Step 2. The browser builds the HTTP request
When you click "Upload", the browser builds a request that looks like this:
Five pieces of information travel together:
- ●The field name (`avatar`). The server looks up which form field this is.
- ●The filename (`cat.jpg`). A suggestion from the browser.
- ●The Content-Type (`image/jpeg`). Also a suggestion from the browser.
- ●The bytes of the file.
- ●The total size (Content-Length).
Important: every one of these five values comes from your computer. Tools like Burp Suite or `curl` can change any of them to anything before sending. The server cannot trust the client.
Step 3. The server receives the request
Server-side code (PHP, Python, Node, Java, anything) reads the request. Here is a tiny PHP example:
The server:
- ●Reads the multipart request.
- ●Saves the bytes to a temporary file (here, `$tmp`).
- ●Moves that file into the upload folder, using the original filename.
After this line, there is a real file on disk at `/var/www/html/uploads/cat.jpg`.
Step 4. The file becomes a URL
Most upload folders are inside the web root: the folder the web server publicly serves. That means a file saved at `/var/www/html/uploads/cat.jpg` is reachable at:
Anyone with that URL can download the file.
Step 5. The server might EXECUTE the file
This is the dangerous step. The web server is configured to run certain file types as code, not just send them as bytes. Examples:
- ●Apache + PHP-FPM ==> any file ending in `.php`, `.phtml`, `.pht`, `.phar`, `.php5` is sent through the PHP engine.
- ●Tomcat ==> any file ending in `.jsp` or `.jspx` is compiled and run as Java.
- ●IIS ==> any file ending in `.asp` or `.aspx` is run as classic ASP or ASP.NET.
- ●Some setups also run `.cgi`, `.pl`, `.py`, `.rb`.
If the file the user uploaded ends in one of these extensions, and the upload folder is inside the web root, then opening the URL no longer just downloads the file. It runs the file.
The whole vulnerability lives in that second diagram. The file is just bytes. The danger is that the server runs the bytes.
Step 6. The server should check the file (but often does not)
A good server checks several things before saving:
Each missing check is a step closer to a working attack.
3. Attack Flow
An attacker follows a careful sequence. Read each step in order.
Step 1. Find an upload form
Anywhere a user can send a file to the server: profile picture, document attachment on a support ticket, image inside a comment, CV upload on a careers page, theme installer in an admin panel, CSV import in a settings page.
Step 2. Send a normal file first
Upload a real `test.jpg`. Note three things:
- ●Did the server accept the file?
- ●What URL is the file served from? (Often the response says "File saved at /uploads/test.jpg".)
- ●What does the response look like when something fails? (Different errors leak the validation logic.)
Step 3. Send a tiny script disguised in the simplest way
Try uploading a file called `shell.php` whose contents are:
Possible server responses:
- ●`200 OK` and saved at `/uploads/shell.php` ==> ALMOST DONE. Skip to step 6.
- ●`400 Bad Request` with "extension not allowed" ==> the server has a filter. Continue to step 4.
- ●`200 OK` but saved with a random filename ==> filter is good. Try other tricks.
- ●Other errors ==> read the message and adapt.
Step 4. Try common bypasses
The single most effective list of variants to try:
Try each one. Watch for which one is accepted.
Step 5. Try Content-Type forgery and content tricks
If the filter is happy with the filename, the server may still check the file body or the MIME type. Bypasses:
- ●Use Burp Suite to change `Content-Type: application/x-php` to `Content-Type: image/jpeg` in the multipart request.
- ●Create a file that starts with bytes that look like a JPEG and then has PHP code after:
This is called a polyglot file. The first bytes pass a "magic bytes" check. The rest of the file contains the code.
Step 6. Visit the file to confirm execution
If the file is saved at `/uploads/shell.phtml`, open in a browser:
Expected response if execution works:
If you see that, the server is running your code.
Step 7. Escalate
Once code runs, the attacker can do anything the web user can do:
- ●Read `/etc/passwd`.
- ●Read `/var/www/.env` (database credentials, API keys).
- ●Open a reverse shell to the attacker's IP.
- ●Read AWS metadata at `http://169.254.169.254/`.
- ●Steal customer data.
Every file upload attack follows that exact heartbeat. Different filters, different bypasses, same outcome.
4. Why Developers Make This Mistake
The developer who wrote this:
did not see a security problem because they were thinking like this:
- ●"The user is sending a picture."
- ●"I checked the extension. That feels enough."
- ●"The folder is just a folder; it stores files."
- ●"Apache runs PHP, but only the PHP I write."
Each of those four thoughts is a mistake. The reasons:
- ●"The user is sending a picture." No. The user is sending bytes. The label "picture" is what the user says, not what the bytes are.
- ●"I checked the extension. That feels enough." No. There are at least nine extensions that Apache runs as PHP (`.php`, `.php3`, `.php4`, `.php5`, `.php7`, `.phtml`, `.pht`, `.phar`, `.phps`). Blacklists never list them all. Allowlists do.
- ●"The folder is just a folder." No. The folder is inside the web root. Web servers run code from any folder where script execution is enabled, which is almost always on by default.
- ●"Apache runs PHP, but only the PHP I write." No. Apache runs any file that has the right extension. It does not know who wrote it.
The deeper reason behind the mistake: developers think about features, attackers think about side effects.
- ●The feature is "save a picture".
- ●The side effect is "create a public URL that runs code if the bytes look like code".
Once you see the side effect, the bug becomes obvious.
5. Beginner Summary
- ●A file upload bug happens when a website lets a user save a file on the server and the server later runs that file as code.
- ●The simplest test is to upload a small file like `shell.php` with the content `<?php system($_GET['c']); ?>`, visit the URL, and see if `id` runs.
- ●Most validation in real apps checks only one thing (the extension OR the MIME header). Attackers bypass that one check with variants like `.phtml`, `.pht`, double extensions, or fake MIME types.
- ●The damage ranges from stored XSS (uploading HTML or SVG) all the way to full server takeover (uploading and executing a PHP, JSP, or ASPX shell).
- ●The fix is layered: allowlist of extensions, MIME + magic byte checks, random filename, storage outside the web root, no script execution in the upload folder.
If you remember those five lines, you have the whole concept.
6. Visual Explanation
The five layers a safe upload should pass
The same diagram if the server is naive
The five things the attacker can change in the request
The vulnerability ladder
Read those four diagrams. They are the whole bug class.
7. Definition
Technical definition. A file upload vulnerability is a class of web application weakness in which a server accepts user-supplied files without enforcing strict validation on the filename, MIME type, magic bytes, content, size, and storage location, allowing an attacker to write arbitrary files on the server, possibly in a location where the web server will execute them as code, leading to outcomes from stored XSS up to remote code execution and host compromise.
Beginner-friendly definition. A file upload bug is when a website lets you upload a file that should not be there, like a PHP script disguised as an image, and the server then runs it.
Why it matters. File upload is one of the most direct paths to remote code execution in modern web apps. It appears in CMS plugins, e-commerce platforms, social networks, document managers, ticketing systems, and any feature that lets users send media. Recent critical incidents include CVE-2025-0520 (ShowDoc unauthenticated RCE, CVSS 9.4), CVE-2025-67260 (Terrapack), CVE-2025-65875 (FPDF AddFont), CVE-2025-12682 (WordPress Easy Upload Files), CVE-2025-52691 (SmarterMail unauthenticated RCE), CVE-2024-30500 (cubewp-framework Zip upload), and the Apache Tomcat partial-PUT family (CVE-2025-24813). The bug class is tracked by MITRE as CWE-434 (Unrestricted Upload of File with Dangerous Type) and CWE-22 (Path Traversal) when filenames are abused.
Common affected systems.
- ●Content Management Systems and their plugin ecosystems
- ●Document managers (ShowDoc, Confluence attachments)
- ●E-commerce platforms (checkout uploads, product images)
- ●Social networks (avatars, cover photos, post media)
- ●Ticketing and CRM systems (attachment fields)
- ●Admin panels with theme or plugin installers
- ●Careers/HR portals with CV upload
- ●APIs that accept base64-encoded files in JSON
If a feature lets a user send bytes that touch the filesystem, file upload may live there.
8. Examples
Five realistic scenarios. Each is written as a small walkthrough, no characters.
Example 1. Profile Picture Upload with a Blacklist
The feature. A social app lets users set an avatar. The server blacklists `.php`, `.php5`, and `.exe`.
The bug. The blacklist is incomplete. Apache also runs `.phtml`, `.pht`, and `.phar` as PHP. Those are not in the list.
The attack step by step.
- ●Upload a file called `shell.phtml` containing `<?php system($_GET['c']); ?>`.
- ●Server accepts.
- ●Visit `https://anastech.com/uploads/shell.phtml?c=id`.
- ●Output: `uid=33(www-data) gid=33(www-data)`.
- ●Replace the content with a reverse shell. Get a terminal on the server.
Example 2. Document Upload Validated by Content-Type
The feature. A document manager accepts `.pdf` and `.docx`. The server reads the `Content-Type` header from the request and trusts it.
The bug. The `Content-Type` value is set by the browser. It is not derived from the bytes. Burp Suite can change it to anything.
The attack step by step.
- ●Prepare a file `shell.php` with PHP code.
- ●Send the upload through Burp.
- ●In Burp Repeater, change the `Content-Type` header from `application/x-php` to `application/pdf`.
- ●Server accepts.
- ●Visit the file URL. PHP runs.
Example 3. Image Upload Validated by Magic Bytes
The feature. An e-commerce site accepts proof-of-purchase images. The server checks the first three bytes of the file. If they equal `FF D8 FF` (JPEG header), it accepts.
The bug. The magic bytes prove only that the file starts like a JPEG. The rest can be anything.
The attack step by step.
- ●Build a polyglot file:
- ●Upload. Magic byte check passes (first three bytes are correct).
- ●File is saved as `pwn.phtml`.
- ●Apache executes `.phtml` as PHP.
- ●Visit the URL. RCE.
Example 4. Resume Upload with No Path Sanitization
The feature. A careers portal accepts resumes and stores them using the original filename.
The bug. The filename can contain `../../../`. The file lands wherever the attacker wants.
The attack step by step.
- ●Send the upload with filename `../../var/www/html/shell.jsp`.
- ●URL-encoded: `..%2f..%2fvar%2fwww%2fhtml%2fshell.jsp`.
- ●The file lands in the web root, not in `/srv/uploads`.
- ●Tomcat compiles and executes the JSP.
- ●RCE.
Example 5. The `.htaccess` Override Trick
The feature. An app blacklists every known executable extension and feels confident.
The bug. The blacklist does not include `.htaccess`. Apache reads `.htaccess` files from any directory and lets them change server behavior in that directory.
The attack step by step.
- ●Upload a file called `.htaccess` with the contents:
- ●Upload a second file called `pwn.anastech` containing `<?php system($_GET['c']); ?>`.
- ●Apache reads the `.htaccess`, learns to treat `.anastech` as PHP inside `/uploads/`.
- ●Visit `https://anastech.com/uploads/pwn.anastech?c=id`. RCE.
Each pattern shows up in real disclosed reports. The mechanics never change.
9. Vulnerable Code
PHP ==> blacklist on extension only
What is wrong:
- ●The blacklist is incomplete. `.pht` and `.phar` are missing.
- ●The filename comes straight from the client (no rename).
- ●The folder is inside the web root.
Fix: switch to allowlist, rename the file to a UUID, save outside web root.
PHP ==> MIME check only
What is wrong: `$_FILES['avatar']['type']` is whatever the browser said. A tool can send any value.
PHP ==> Magic-byte check only
What is wrong: the bytes prove only the first three bytes look like a JPEG. The filename can still be anything (including `.phtml` or `.htaccess`).
Python (Flask) ==> Trusting the filename
What is wrong: `f.filename` is whatever the client said. `os.path.join(UPLOAD_DIR, '../../etc/anything')` silently escapes the upload directory.
Python (Flask) ==> Last-extension allowlist with a flaw
What is wrong: only the last extension is checked. `shell.php.jpg` passes (`.jpg` is the last extension), and Apache with `AddHandler application/x-httpd-php .php` will still execute it as PHP.
Node.js (Express + Multer) ==> No filter
What is wrong: no `fileFilter`. No rename. File lands in a public folder.
Node.js (Express) ==> Insufficient extension check
What is wrong: only the last extension is checked. `shell.ejs.png` passes. If a downstream service reads the file by content type rather than extension, the EJS code may still run.
Java (Servlet) ==> Trusting the submitted filename
What is wrong: `part.write` writes inside the deployed web app. A `.jsp` file is compiled by Tomcat on first request.
Java (Spring Boot) ==> Wrong content-type check
What is wrong: `file.getContentType()` reflects the client header. Forge in Burp.
C# (.NET Core) ==> Trusting filename, saving inside wwwroot
What is wrong: `Path.Combine` does not normalize traversal. `file.FileName` can contain `..\\`. The webroot is served, and `.aspx`, `.cshtml`, `.razor` files are executed.
Ruby (Rails) ==> Permissive content_type with no path safety
What is wrong: `public/uploads/` is served directly. `original_filename` is attacker-controlled.
Go (net/http) ==> Filename concat
What is wrong: `handler.Filename` is client-supplied. Traversal works.
The universal pattern across languages
Steps 2, 3, and 4 are where the bug is born. Every time.
10. Detection
Detection is the step where you confirm a bug exists. Walk through each test in order. Stop only when you have a clear hit.
Step 1. List every upload point
A typical web app has several. Tick each box you can find:
Step 2. Baseline a normal upload
For each upload point:
- ●Send a real `test.jpg`. Note the response.
- ●Note the final URL of the file.
- ●Note whether the response echoes the filename, returns a UUID, or hides the path.
Step 3. Send the simplest dangerous file
Upload `shell.php` with the content `<?php echo 'pwn-marker'; ?>`. Watch:
- ●Was it accepted? If yes, go to step 6.
- ●Was it rejected? Read the error. It will hint at the filter.
Step 4. Walk the bypass ladder
For each rejection, try the next variant:
Step 5. Try MIME and content tricks
If the filename filter is good, try the body:
- ●In Burp, change `Content-Type` to `image/jpeg` even when the file is PHP.
- ●Make a polyglot file:
- ●Use ExifTool to put PHP inside the EXIF comment of a real JPEG:
Step 6. Verify execution
After every successful upload, fetch the file URL:
- ●If response is `<?php echo 'pwn-marker'; ?>` ==> file is served as text, no execution. (Stored source disclosure, low.)
- ●If response is `pwn-marker` ==> code executed. (RCE.)
- ●If response is `200 OK` with no body ==> code executed but printed nothing. Try `?c=id`.
- ●If response is `403` ==> file uploaded but folder blocks execution.
- ●If response is `404` ==> wrong URL. Look at where the file actually landed.
Step 7. Confirm impact
Once execution works, upload a small command shell and run:
Each one gives a different piece of evidence. Use them together in the report.
Burp Suite checklist
- ●Intercept the upload.
- ●Send to Repeater.
- ●Modify ONE thing per request: filename, then Content-Type, then bytes. Never two at once.
- ●Use Intruder with the bypass list from step 4.
- ●Use the Upload Scanner Burp extension (Florian Maier) for automated coverage.
Automated tools
- ●fuxploider ==> https://github.com/almandin/fuxploider ==> tries 200+ filename variants and confirms execution.
- ●Burp Upload Scanner ==> bundled bypass payloads.
- ●Nuclei templates tagged `file-upload` ==> known CMS bugs.
- ●wpscan ==> for WordPress plugins with known upload CVEs.
Quick fuxploider command:
Indicators that an upload is likely to be vulnerable
- ●"Upload your profile picture" with no obvious size restriction.
- ●Response includes the path or URL of the saved file.
- ●Response echoes the filename back unchanged.
- ●Directory listing of `/uploads/` is accessible.
- ●Old plugin or CMS version visible in `Server:` header (look up the version for known CVEs).
- ●Endpoint accepts a wide range of file types.
- ●The application has a "media library", "import", or "theme upload" feature.
Train your eye. Every upload form is a possible code-execution engine.
11. Exploitation
This is where you turn detection into impact. Read each technique carefully.
Workflow
Advanced techniques (numbered 1 to 30)
1. Extension allowlist bypass via double extensions
Servers that check "is the last extension safe?" miss filenames like:
2. Null byte truncation
Older PHP and Java versions stopped reading at a null byte:
Validator sees `.jpg`. Filesystem sees `shell.php`. Mostly patched on modern stacks, still works on legacy.
3. URL-encoded and double-encoded dots
If the validator decodes once but the filesystem uses the encoded version:
4. Trailing character trick
Apache strips trailing dots and spaces:
5. Semicolon trick on IIS
IIS 6 and some IIS 7 configs treat the part before `;` as the executable name:
6. IIS lesser-known extensions
When `.asp` and `.aspx` are blocked, try:
7. PHP-executable extension family
Apache + PHP-FPM commonly map all of these:
`.phar` (PHP archive) is the underused gem. `.phps` returns source if configured.
8. JSP variants on Tomcat
`.jspx` is XML-based JSP and often missing from blacklists.
9. Polyglot files
A polyglot is valid as two formats at once. JPEG + PHP:
GIF + PHP:
ExifTool can hide PHP in EXIF metadata of a real image:
10. SVG stored XSS
If RCE is not possible, SVG upload usually is. SVG is XML, XML can carry JavaScript:
When another user (especially admin) views the SVG, the script runs in the application origin.
11. HTML and .eml upload for XSS
Upload as `pwn.html`. Some apps even render `.eml` as HTML.
12. .htaccess override on Apache
Upload `.htaccess` with this content. Then upload `shell.anastech`. RCE.
13. web.config override on IIS
Upload `web.config` to a writable directory:
14. .user.ini override on PHP-FPM
If Apache or PHP-FPM honors `.user.ini`, drop one to set `auto_prepend_file`:
Combined with a polyglot GIF, this gives RCE through every PHP page in that folder.
15. Path traversal in filename
When filename is concatenated into a path:
The shell lands wherever the attacker wants.
16. Zip slip and archive bombs
If the server unzips uploaded archives, name the entries with traversal:
Upload `exploit.zip`. If the extractor does not sanitize entry names, the shell lands in webroot. CVE-2024-30500 (cubewp-framework) is a real-world example.
17. Race condition bypass
Some servers upload to a public location, validate, then delete on failure. For a few hundred milliseconds the file is live:
18. PUT-method upload
If `PUT` is enabled on a directory, no upload form is needed:
CVE-2025-24813 (Apache Tomcat) is the modern partial-PUT trick: writes to a temp file with a predictable name that can be triggered for RCE.
19. Content-Type forge
The validator that trusts `request.files['file'].content_type`:
20. Multi-boundary filename confusion
Some parsers handle multi-boundary or repeated headers poorly:
Validator reads the first filename, storage reads the second.
21. Antivirus-evasion encoded payload
When ClamAV runs on uploads, signatures look for typical shell strings. Encode:
Or base64:
22. Image resize / re-encode bypass
If the server re-encodes uploaded images, polyglot payloads die. Counter:
- ●Place payload in EXIF sections the resizer does not touch.
- ●Use a format the resizer cannot handle (AVIF, BMP, TIFF) so it falls back to "save as is".
- ●Exploit the resizer itself via ImageMagick (CVE-2016-3714 "ImageTragick" family).
23. SSRF via FFmpeg HLS
If the server runs FFmpeg on uploaded media, build an HLS playlist:
Upload as `pwn.m3u8`. FFmpeg fetches the inner URLs server-side. AWS metadata leaks. TikTok paid $2,727 for this on their video upload.
24. XXE via office documents
Office documents (`.docx`, `.xlsx`, `.pptx`) are zipped XML. Some servers parse them server-side for previews. Inject:
If the parser resolves external entities, file disclosure follows.
25. Encoding and case combinations
26. URL-based upload races
Some apps fetch a file by URL ("import from URL"):
- ●Race the fetcher: serve different content on the second request than the first.
- ●Use redirects to chain into internal SSRF.
27. Stored XSS via filename reflection
If the server reflects the filename in HTML:
Extension check passes (`.jpg`). The filename becomes XSS when the avatar list page renders the name.
28. Bypassing CDN-side filters
If the upload goes through Cloudflare or AWS WAF, upload with a benign extension and rename later. OR upload directly to the origin S3 bucket (often misconfigured to allow public writes).
29. Multi-stage stager
When uploads are scanned but execution is on a separate route, upload a stager that fetches the real payload at runtime:
The stager is small and trivial. AV matches nothing because the dangerous payload is fetched later.
30. JNDI in filename (Log4Shell-adjacent)
When the server logs the filename through Log4j (older versions):
Logged ==> Log4j evaluates ==> remote class load ==> RCE. Old but still found in legacy systems.
These 30 techniques are the modern upload hunter's toolkit. Combine them. The juiciest bugs come from chaining three or four.
12. Proof of Concept
This section shows every PoC format you might need.
Burp Suite step by step
Python PoC (detection sweep)
Python PoC (confirm RCE)
Bash PoC (one-liner shell drop)
Bash PoC (reverse shell)
Polyglot JPEG/PHP PoC
EXIF-embedded PHP PoC
.htaccess override PoC
Zip slip PoC
PowerShell PoC
Node.js PoC
fuxploider PoC
The tool fingerprints the validation strategy, walks through 200+ bypass payloads, and drops you into an interactive shell when one works.
13. Payloads
Web shell one-liners
PHP:
ASP / ASPX:
JSP:
Python (CGI / mod_wsgi):
Ruby (ERB / Rack):
Node.js (EJS):
Perl CGI:
Filename bypass variants
Polyglot generation (GIF + PHP)
Polyglot generation (PNG + PHP)
ExifTool embedded shell
.htaccess payload
.user.ini payload
web.config payload
Zip-slip archive builder
SVG stored XSS
HTML file XSS
XXE via DOCX
FFmpeg HLS SSRF
Reverse shell PHP payloads
Antivirus-evasion payload (encoded)
PUT-method upload
Tomcat PUT (CVE-2025-24813 family)
The payload is whatever the engine executes. The attack is whatever the engine can do.
14. Wordlists and Payload Libraries
- ●PayloadsAllTheThings ==> Upload Insecure Files ==> https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20Insecure%20Files
The definitive collection of upload bypass payloads, shells, polyglots, and configuration overrides.
- ●fuxploider ==> https://github.com/almandin/fuxploider
Automated upload-bypass tool with 200+ filename variants and execution confirmation.
- ●Upload Scanner (Burp BApp) ==> https://github.com/modzero/mod0BurpUploadScanner
Burp Suite extension that runs the full bypass arsenal against any upload endpoint.
- ●HackTricks File Upload ==> https://book.hacktricks.xyz/pentesting-web/file-upload
Continuously updated cheat sheet for every modern upload trick.
- ●PortSwigger File Upload Vulnerabilities ==> https://portswigger.net/web-security/file-upload
The canonical learning resource with hands-on labs.
- ●OWASP Unrestricted File Upload ==> https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload
Definition, impact, and high-level prevention guidance.
- ●OWASP File Upload Cheat Sheet ==> https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html
Defender's checklist for safe upload handling.
- ●SecLists ==> Discovery / Web Content ==> https://github.com/danielmiessler/SecLists/tree/master/Discovery/Web-Content
Useful for finding upload endpoints and exposed `/uploads/` directories.
- ●SecLists ==> Fuzzing ==> File-Extensions-Most-Common ==> https://github.com/danielmiessler/SecLists/tree/master/Fuzzing
Wordlists of file extensions for testing handler mappings.
- ●Anas Magane Pentesting Notes ==> File Upload ==> https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP/File_Upload
Author's original lab notes and bypass cheatsheet.
- ●Web Shells Repository (tennc) ==> https://github.com/tennc/webshell
Large library of shells for every language. Use only for authorized testing.
- ●Sushant Total OSCP Guide ==> Bypass Image Upload ==> https://sushant747.gitbooks.io/total-oscp-guide/content/bypass_image_upload.html
Classic walkthrough of polyglot and EXIF tricks.
These tools and lists form the modern upload hunter's loadout.
15. Impact
- ●Remote Code Execution. The primary outcome when the uploaded file is a server-side script and the server is configured to execute it. Full server compromise, lateral movement, persistence via cron, systemd, or backdoored cron tabs.
- ●Stored Cross-Site Scripting. Uploading HTML, SVG, or any file rendered as HTML can lead to persistent XSS. Particularly dangerous against admin panels.
- ●Local File Overwrite. Filename traversal allows the attacker to overwrite critical files (config, logs, source code).
- ●Source Code Disclosure. When the server saves but does not execute, fetching the file may return raw source as text, leaking secrets, credentials, and logic.
- ●Information Disclosure. Uploaded files may leak via directory listings, search engines, or chained Path Traversal bugs.
- ●Denial of Service. Large files fill disk. Many small files exhaust inodes. Decompression bombs in zip uploads exhaust memory.
- ●Phishing Host. Attackers host malicious HTML/PDF/JS on the target's legitimate domain.
- ●Malware Distribution. Hosting EXE, APK, DMG, or ISO files for malware distribution under a trusted brand.
- ●Pivot to Internal Network. RCE on a public-facing app is the foothold for attacking internal services.
- ●Cloud Credential Theft. Once on the box, the attacker reads instance role credentials from `169.254.169.254` (AWS), `metadata.google.internal` (GCP).
- ●Compliance Disaster. Violations of GDPR, HIPAA, PCI DSS, SOC 2 when uploaded files land in regulated environments.
- ●Persistent Backdoor. A web shell uploaded once survives many restarts because it lives in `/var/www/html/uploads/` and is rarely audited.
A single critical file-upload RCE has wiped out entire SaaS environments and led to nine-figure breach reports.
16. Prevention
Vulnerable Example
Secure Example (Production-Grade)
Key changes:
- ●Allowlist of extensions, not blacklist.
- ●MIME and magic bytes verified server-side.
- ●Random filename, original discarded.
- ●Storage outside the web root.
- ●Re-encoding to strip polyglot payloads.
- ●Download endpoint with a hard-coded Content-Type.
Eight Rules to Eliminate File Upload Bugs
- ●Rule 1. Use an allowlist of extensions. Never a blacklist.
- ●Rule 2. Verify the MIME and the magic bytes server-side. Never trust the client.
- ●Rule 3. Rename every uploaded file to a server-generated random name.
- ●Rule 4. Store files outside the web root. Serve them through a dedicated endpoint with a fixed Content-Type.
- ●Rule 5. Disable script execution in the upload directory.
- ●Rule 6. Re-encode images server-side to strip polyglot payloads.
- ●Rule 7. Run antivirus / file scanning (ClamAV, YARA) on every upload.
- ●Rule 8. Enforce strict size limits and quotas.
Developer Checklist
Server Configuration Examples
Apache (disable PHP execution in uploads):
Nginx (deny script execution):
IIS (remove handlers):
17. Real-World Cases
CVE-2025-0520 (ShowDoc Unrestricted File Upload, CVSS 9.4)
ShowDoc versions before 2.8.7 contained an unauthenticated file upload vulnerability allowing attackers to upload arbitrary PHP files and achieve full RCE. The flaw stemmed from improper file-extension validation. Mass-exploited in the wild after public disclosure.
CVE-2025-67260 (Terrapack File Upload RCE)
Multiple components of the Terrapack software suite suffered from insufficient validation of uploaded file types and content. Authenticated low-privilege attackers could upload web shells leading to arbitrary code execution.
CVE-2025-65875 (FPDF AddFont RCE)
The popular PHP PDF library FPDF (v1.86 and earlier) shipped with an `AddFont()` function that failed to validate uploaded font files. Attackers could disguise PHP code as a font resource and trigger RCE.
CVE-2025-12682 (WordPress Easy Upload Files, Unauthenticated)
The Easy Upload Files During Checkout plugin (versions up to 2.9.8) allowed unauthenticated attackers to upload arbitrary JavaScript files via the `file_during_checkout` function. Combined with WordPress rendering, attackers achieved stored XSS and RCE on some configurations.
CVE-2025-52691 (SmarterMail Unauthenticated File Upload RCE)
SmarterTools SmarterMail Build 9412 and earlier shipped with an unauthenticated arbitrary file upload allowing pre-auth RCE. Patched in Build 9413.
CVE-2025-24813 (Apache Tomcat Partial PUT to RCE)
A subtle bug in Tomcat's partial PUT implementation allowed attackers to write security-sensitive files and inject content into them.
CVE-2024-30500 (WordPress cubewp-framework Zip Upload)
The cubewp-framework plugin accepted zip uploads and extracted them without validating inner file types. Attackers embedded `.php` files in the archive and achieved RCE after extraction.
HackerOne: Starbucks RCE
Unrestricted file upload on `mobile.starbucks.com.sg` led to RCE on the server. 244 upvotes.
HackerOne: TikTok FFmpeg HLS SSRF ($2,727)
A crafted HLS playlist (`.m3u8`) uploaded to TikTok's video pipeline made FFmpeg fetch arbitrary URLs including the AWS metadata endpoint, leaking IAM credentials.
HackerOne: HackerOne Itself ==> RCE in Profile Picture Upload
The bug bounty platform itself had an RCE in its profile-picture upload. Reported, fixed, and disclosed publicly.
HackerOne: Razer Admin Default Password ==> Image Upload Shell
Default admin credentials + image upload feature led to web shell upload and backend takeover. 199 upvotes.
HackerOne: Linktree No Validation on Image Upload
Linktree accepted any file type via the image upload feature, enabling content hosting under a trusted brand.
HackerOne: Semrush Unrestricted File Upload
The report image upload on Semrush accepted PHP files. 131 upvotes.
HackerOne: U.S. DoD Null Byte Truncated File Extension
A legacy PHP version on a DoD website truncated `shell.php%00.jpg` at the null byte. RCE achieved.
HackerOne: Mail.ru Shell Upload ($500)
A partner-only service had an upload endpoint with weak validation.
HackerOne: Concrete CMS SVG with HTML Included
SVG upload led to stored XSS that hit admins.
Lessons across all these cases:
- ●File upload bugs ship in every CMS, every framework, every plugin ecosystem.
- ●The "validation" almost always has a hole.
- ●Bug bounty payouts for upload RCE regularly hit 5,000 to 75,000 dollars.
- ●The fix is universally the same: allowlist, rename, no execution in upload directories.
- ●New research keeps producing fresh bypass classes (zip slip, polyglot, partial PUT, FFmpeg HLS).
18. References
- ●OWASP Unrestricted File Upload ==> https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload
- ●OWASP File Upload Cheat Sheet ==> https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html
- ●PortSwigger Web Security Academy ==> File Upload ==> https://portswigger.net/web-security/file-upload
- ●MITRE CWE-434 ==> Unrestricted Upload of File with Dangerous Type ==> https://cwe.mitre.org/data/definitions/434.html
- ●MITRE CWE-22 ==> Path Traversal ==> https://cwe.mitre.org/data/definitions/22.html
- ●PayloadsAllTheThings ==> Upload Insecure Files ==> https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20Insecure%20Files
- ●fuxploider ==> https://github.com/almandin/fuxploider
- ●Burp Upload Scanner ==> https://github.com/modzero/mod0BurpUploadScanner
- ●HackTricks File Upload ==> https://book.hacktricks.xyz/pentesting-web/file-upload
- ●CVE-2025-0520 ShowDoc RCE ==> https://www.sentinelone.com/vulnerability-database/cve-2025-0520/
- ●CVE-2025-67260 Terrapack RCE ==> https://www.sentinelone.com/vulnerability-database/cve-2025-67260/
- ●CVE-2025-65875 FPDF AddFont RCE ==> https://www.sentinelone.com/vulnerability-database/cve-2025-65875/
- ●CVE-2025-12682 WordPress Easy Upload Files RCE ==> https://www.sentinelone.com/vulnerability-database/cve-2025-12682/
- ●CVE-2025-24813 Tomcat Partial PUT RCE ==> https://hackerone.com/reports/3031518
- ●HackerOne TOPUPLOAD list ==> https://github.com/reddelexc/hackerone-reports/blob/master/tops_by_bug_type/TOPUPLOAD.md
- ●Top 25 RCE Bug Bounty Reports (Cristian Cornea) ==> https://corneacristian.medium.com/top-25-rce-bug-bounty-reports-bc9555cca7bc
- ●Anas Magane Pentesting Notes ==> https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP/File_Upload
19. Practical Labs
SOON.
The ANAS EDUCATION lab environment for File Upload is currently being built. You will soon practice:
- ●Naked PHP upload (no validation at all)
- ●Extension-blacklist bypass with `.phtml` / `.pht` / `.phar`
- ●Case-bypass with `.pHp`
- ●Double extension `shell.php.jpg`
- ●Null byte truncation `shell.php%00.jpg` (legacy)
- ●MIME-only validator bypass with Burp Repeater
- ●Magic-byte-only validator bypass with polyglot JPEG/PHP
- ●EXIF-embedded PHP shell with ExifTool
- ●`.htaccess` override on Apache
- ●`web.config` override on IIS
- ●`.user.ini` `auto_prepend_file` trick
- ●Path traversal in filename to escape `/uploads/`
- ●Zip-slip via WordPress-style importer
- ●Race condition in scan-then-delete handlers
- ●SVG stored XSS that hijacks an admin session
- ●FFmpeg HLS SSRF on a video upload pipeline
- ●Office docx with XXE on a thumbnail processor
- ●JSP upload on Tomcat with partial PUT
- ●Image-resize bypass using AVIF/BMP fallback
- ●Antivirus evasion via base64-encoded shell
In the meantime, practice on PortSwigger Web Security Academy labs:
- ●APPRENTICE: Remote code execution via web shell upload
- ●APPRENTICE: Web shell upload via Content-Type restriction bypass
- ●PRACTITIONER: Web shell upload via path traversal
- ●PRACTITIONER: Web shell upload via extension blacklist bypass
- ●PRACTITIONER: Web shell upload via obfuscated file extension
- ●PRACTITIONER: Remote code execution via polyglot web shell upload
- ●EXPERT: Web shell upload via race condition
Stay tuned.
20. Cheat Sheet
Print this. Tape it next to your monitor. Live it.
21. Exam (30 Questions)
Format: Multiple Choice. Platform randomly selects 20. Scoring: 0 to 13 fail, 14 to 15 retry, 16 to 20 pass.
Q1. What is the most common impact of a critical file upload vulnerability? A. Open Redirect B. Remote Code Execution C. CSRF D. UI Redress Answer: B.
Q2. Which CWE matches Unrestricted File Upload most closely? A. CWE-79 B. CWE-89 C. CWE-434 D. CWE-22 Answer: C.
Q3. The browser-sent Content-Type header during a file upload is: A. Computed from the file's bytes B. Set by the client and trivially forged C. Validated by the operating system D. Cryptographically signed Answer: B.
Q4. Which is NOT a PHP-executable extension on a typical Apache + PHP-FPM setup? A. .php B. .phtml C. .phar D. .jpg Answer: D.
Q5. When developers blacklist `.php` only, the simplest bypass is: A. Encrypt the file B. Try alternate executable extensions like `.phtml`, `.pht`, `.php5` C. Upload the file twice D. Send it via email instead Answer: B.
Q6. A "polyglot" file is: A. Translated into multiple languages B. A valid file in two or more formats simultaneously C. Encrypted with multiple keys D. Uploaded by multiple users Answer: B.
Q7. Which tool embeds PHP code inside the EXIF metadata of a real JPEG? A. nmap B. ExifTool C. sqlmap D. john Answer: B.
Q8. When the server checks only the last extension after the final dot, the bypass is: A. Upload `shell.php` directly B. Upload `shell.php.jpg` and rely on Apache's parse of every extension C. Use HTTPS D. Encode the filename in base64 Answer: B.
Q9. The `.htaccess` upload trick achieves RCE by: A. Compressing the shell B. Re-mapping a custom extension to be executed as PHP within Apache C. Encrypting the shell D. Renaming the file Answer: B.
Q10. Which validation strategy is the MOST robust? A. Blacklist of dangerous extensions B. Client-supplied Content-Type check C. Allowlist of extensions PLUS MIME and magic-byte verification PLUS rename PLUS storage outside webroot D. File size limit only Answer: C.
Q11. On IIS, even when `.aspx` is blocked, which lesser-known extension can still execute ASP code? A. .css B. .cer C. .jpg D. .docx Answer: B.
Q12. The semicolon trick `shell.asp;.jpg` is famously exploited on: A. Nginx B. IIS 6 and misconfigured IIS 7 C. Apache only D. Tomcat only Answer: B.
Q13. A `.user.ini` upload achieves RCE on PHP-FPM via: A. Database connection abuse B. The `auto_prepend_file` directive forcing every PHP request to include the attacker's file C. SQL injection D. Session hijacking Answer: B.
Q14. Zip Slip is: A. A network protocol B. Path traversal in archive entry names that lets the extractor write files outside the target directory C. A type of DoS D. A reverse shell Answer: B.
Q15. Race conditions in file uploads happen when: A. Two users upload at the same time B. The server writes the file to a public location first, validates after, and the attacker fetches it in the brief window before deletion C. Two extensions appear in the filename D. The CDN serves the file Answer: B.
Q16. Which CVE represents the SmarterMail unauthenticated upload RCE in 2025? A. CVE-2025-52691 B. CVE-2025-0001 C. CVE-2022-22954 D. CVE-2023-36845 Answer: A.
Q17. TikTok paid a bounty for an upload bug that abused which component? A. WAF B. FFmpeg processing of HLS playlists, leading to SSRF C. Antivirus D. Burp Suite Answer: B.
Q18. When the server re-encodes uploaded images, the polyglot trick typically fails because: A. The original pixel data is replaced and embedded PHP is stripped B. The image is rotated C. The image is encrypted D. The image is signed Answer: A.
Q19. A file upload that lands in a directory listed in `.htaccess` with `Options -ExecCGI` and no PHP handler will: A. Execute PHP normally B. NOT execute PHP because script execution is disabled there C. Crash the server D. Disable HTTPS Answer: B.
Q20. The safest filename to give to an uploaded file on disk is: A. The original filename B. A server-generated UUID or random hex string with a controlled extension C. The user's email address D. The MD5 of the user password Answer: B.
Q21. Stored XSS via file upload is most commonly achieved with: A. JPEG files B. SVG files containing `<script>` tags C. Encrypted ZIP files D. Empty TXT files Answer: B.
Q22. A `web.config` upload on IIS allows RCE by: A. Resetting the database B. Mapping arbitrary extensions to script handlers within that directory C. Disabling HTTPS D. Generating new keys Answer: B.
Q23. Which is true about MIME type validation? A. It is sufficient on its own B. It is just one of several layers and must be combined with extension allowlisting, magic bytes, and content scanning C. It is irrelevant D. It blocks XSS automatically Answer: B.
Q24. Apache Tomcat's CVE-2025-24813 abused: A. WebDAV PUT B. Partial PUT temp file naming, allowing path manipulation and content injection C. SQL injection D. CSRF Answer: B.
Q25. The PortSwigger Apprentice lab "Web shell upload via Content-Type restriction bypass" expects you to: A. Find SQL injection first B. Forge the Content-Type header in Burp to image/jpeg while uploading a `.php` C. Use a reverse proxy D. Solve a CAPTCHA Answer: B.
Q26. A simple PHP web shell that runs commands via a `c` query parameter is: A. `<?php system($_GET['c']); ?>` B. `<?php sleep(10); ?>` C. `<?php echo 'hello'; ?>` D. `<?php phpinfo(); ?>` Answer: A.
Q27. Storing user uploads on a separate domain like `uploads.anastech.com` helps because: A. It hides the files B. Any XSS from uploaded HTML/SVG cannot reach the main app via same-origin policy C. It compresses the files D. It encrypts the files Answer: B.
Q28. Which PortSwigger lab requires polyglot construction? A. Web shell upload via Content-Type restriction bypass B. Web shell upload via path traversal C. Remote code execution via polyglot web shell upload D. Web shell upload via race condition Answer: C.
Q29. The MOST effective single prevention rule is: A. Hide the upload form B. Allowlist extensions, rename files, and store outside the web root with execution disabled C. Use HTTPS only D. Set a CAPTCHA Answer: B.
Q30. The MOST important takeaway about file upload: A. Browsers protect users B. An uploaded file is just bytes; the danger comes from where it lands and how the server interprets it C. Antivirus is enough D. Only Wordpress is affected Answer: B.
22. Certificate Requirements
To earn the ANAS EDUCATION File Upload Certificate, the student must:
- ●Complete every lesson in this module.
- ●Complete all practical labs once released.
- ●Pass the exam with at least 16 out of 20.
Only then will the course be marked complete on the student dashboard.
23. Important Notes
Common Beginner Mistakes
- ●Testing only `shell.php` and giving up at the first error.
- ●Trusting the "Uploaded successfully" response without fetching the file URL to confirm execution.
- ●Forgetting to test path traversal in the filename.
- ●Not trying `.htaccess`, `web.config`, and `.user.ini`.
- ●Reporting "I uploaded a PHP file" as the bug without proving execution.
- ●Confusing stored XSS via upload (rendered HTML/SVG) with RCE (executed server-side script).
- ●Forgetting that Apache parses every extension in `shell.php.jpg`.
- ●Not toggling Content-Type in Burp to test MIME-only validators.
Pentester Tips
- ●Always test the file URL after upload. "Saved" without "executed" is a low-severity finding.
- ●Identify the server before throwing payloads. Apache, Nginx, IIS, and Tomcat each have different mappings.
- ●When stuck, try `.htaccess` and `.user.ini` last. They often bypass clever extension filters.
- ●Use fuxploider as a sanity check, but verify every finding manually.
- ●Combine upload bugs with path traversal, SSRF, and XXE for chain reports.
Bug Bounty Tips
- ●Upload RCE typically pays 5,000 to 75,000 dollars depending on the target.
- ●Always escalate to host compromise, not just "I uploaded a shell".
- ●Show the impact: read `/etc/passwd`, the `.env` file, the cloud metadata.
- ●Marketing automation, CMS plugins, white-label SaaS, and ticketing tools are the highest-paying upload hunting grounds.
- ●Old WordPress plugins are upload-RCE goldmines. The Patchstack monthly competition is a great training ground.
- ●Look for "import", "restore", "theme installer", and "plugin upload" features in admin areas first.
Red Team Notes
- ●Upload RCE on a public-facing app is one of the cleanest paths to initial access.
- ●The payload is the exploit. No malware delivery needed.
- ●EDR rarely flags a benign-looking `.phtml` or `.phar` upload.
- ●Combine upload RCE with cloud metadata SSRF for credentials and lateral movement.
- ●Persistence via shells in `/var/www/html/uploads/` is silent and survives many restarts.
Real-World Advice
- ●When response code is `0` from your reverse shell stager, the command ran but is detached. Check your listener.
- ●When response code is `403`, the file uploaded but the directory blocks execution.
- ●When response code is `500`, your PHP has a syntax error. Test the shell locally first.
- ●Always check for `disable_functions` in `phpinfo()` output. If `system()` is disabled, switch to `popen()`, backticks, or `proc_open()`.
- ●Modern PHP-FPM often runs as `www-data` with no shell. Use `/bin/sh` not `/bin/bash` until you upgrade the shell.
Things to Remember During Exams
- ●CWE-434 ==> Unrestricted File Upload.
- ●`<?php system($_GET['c']); ?>` is the universal canary.
- ●Apache executable PHP extensions: `.php`, `.phtml`, `.pht`, `.phar`, `.php5`, `.php7`, `.phps`.
- ●Allowlist > Blacklist. Always.
- ●The five validation layers: extension, MIME, magic bytes, content, storage location.
- ●Polyglot files defeat magic-byte-only validators.
- ●`.htaccess` overrides server config inside a directory.
- ●`.user.ini` `auto_prepend_file` is the silent killer.
Things to Remember During Real Assessments
- ●Get explicit written permission before throwing reverse shells.
- ●Use benign payloads (`id`, `whoami`, `hostname`) first to confirm execution without damage.
- ●Never run reverse shells against production without a clear scope statement allowing them.
- ●Save the full HTTP request/response pair with the multipart boundaries intact.
- ●Clean up: remove `/tmp/shell.sh`, the uploaded shell, the `.htaccess` override, and any other artifacts.
Frequently Confused Concepts
- ●File Upload vs Path Traversal. Upload writes new content; traversal reads existing content. Together they are catastrophic.
- ●Stored XSS via Upload vs RCE. XSS executes in the browser of another user; RCE executes on the server itself.
- ●Antivirus vs Allowlist. AV is signature-based and easy to evade; allowlist denies the dangerous class entirely.
- ●Polyglot vs Encrypted Payload. Polyglot is valid in two formats; encrypted is one format that needs a decoder.
- ●Stored on Disk vs Served by Web Server. A file can be on disk and not reachable; only files in the web root or behind a download endpoint are served.
Interview Tips
- ●Explain file upload without the word "shell" first. Many interviewers test whether you can teach simply.
- ●Cite CVE-2025-0520 (ShowDoc), CVE-2025-52691 (SmarterMail), and Starbucks (HackerOne) as recent real-world examples.
- ●Mention CWE-434 and the five validation layers.
- ●Always finish with the defense: allowlist, rename, store outside webroot, disable execution.
- ●Be ready to draw the safe-vs-vulnerable code from memory.
Key Takeaways
- ●An uploaded file is just bytes; the danger is in where it lands and how the server interprets it.
- ●The bug class is universal across every language and every CMS.
- ●Detection is one probe: upload a script, fetch the URL, look for execution.
- ●Escalation depends on the server, but the principle is the same: from any execution primitive, walk to a reverse shell.
- ●The fix is one architectural rule: user-supplied files are inert data, never executable code.
24. Final Word from Your Instructor
File upload is the vulnerability that turns innocent media features into total server compromise.
Every time a developer writes:
A new file upload bug is born somewhere in the world.
Every time someone uploads `.phtml` and watches `id` come back, a new finding is documented.
Your job is to look at any upload form and ask three questions, in this order:
- ●Where does the file land on disk?
- ●Who is allowed to choose the filename?
- ●Does the server treat any of these extensions as code?
If you can answer those three questions about a feature, you know whether it is safe.
When you see a profile picture uploader, ask: "What does the server do with these bytes?"
When you see a CV upload on a careers page, ask: "Does this PDF parser run on the server with shell access?"
When you see a CMS theme installer, ask: "Does the framework unzip this archive without sanitizing entry names?"
When you see a video upload, ask: "Does FFmpeg fetch URLs from inside this file?"
When you see a PDF previewer, ask: "Does the parser resolve XML entities?"
If the answer takes you to a place where uploaded bytes become server code, you have found a bug worth tens of thousands of dollars.
The polyglot JPEG/PHP trick is one of the most reliable RCE techniques in modern engagements. Memorize it.
The `.htaccess` override is the silent killer when extension blacklists look airtight. Memorize it.
The `.user.ini` `auto_prepend_file` chain is the move that wins when even `.htaccess` is blocked. Memorize it.
The zip-slip on legacy plugin importers is still paying bounties in 2026. Memorize it.
The fingerprinting table is your map. The payload arsenal is your toolkit. The mindset is your superpower.
- ●Welcome to the upload underworld. Welcome to the bug class where a single twelve-byte file tells the whole story.
- ●Go hunt.