July 17, 2026
File Upload Bypass On Indrive
welcome to my first write-up. I started bug hunting about 3 months ago, and this was one of my first findings, so I would love to share it.

By Mahmoud Elsaidy
3 min read
Let's start with the good stuff.
I was testing on Indrive. The program was going to end in about a month at the time (bad choice on my part). I found a subdomain for "Current Opportunities" for countries around the world. There was a form where you could upload your CV, so I started testing it. I started with the client-side validation.
The form accepted MS Word, WordprocessingML, and PDF files only (.doc, .docx, .pdf). Let's remove those restrictions.
Here the server calculates the file size, content type, and the checksum of the file. This will be important later.
As expected, the server rejected the request.
So let's upload a valid CV, like a PDF, and see what is happening under the hood in Burp. The server sends two requests.
A lot is happening, right? For me it was. The thing that was making me go insane was figuring out how the content of the PDF was being sent to the server, because it wasn't in the second request. It only had the file name, email, and a few other fields. We'll come back to this later. Let's test something else for now.
So I started modifying the first request by changing the file extension to .php and changing the Content-Type. All of them returned HTTP 200.
When the server accepted those values without any restriction, I looked at the request from my first attempt to upload a PHP file (Image 2). It turns out the checksum and the file size were calculated on the client side, and the server accepted them.
Wait a minute… what is Amazon S3?
The response mentioned direct_upload. After doing a bit of searching, I learned what an Amazon S3 bucket is.
That also answered the question that had been driving me crazy. The PDF wasn't being sent in the second request at all. Instead, it was uploaded directly to the URL returned in the direct_upload response, and only after that did the application send the file's metadata to the server.
The moment I realized that my RCE dream was gone :(
I visited the URL to see the request in Burp.
From my research, I found out that I could upload the file to the server using a PUT request, so I tried sending a PHP file, it didn't work.
So I added the Content-Type and Content-Length headers, Still didn't work.
I started searching for what SignatureDoesNotMatch meant and how to solve it. The answer was actually pretty obvious. I found out that the request needed the checksum in the Content-MD5 header. To calculate it on my own i will have to MD5 hash of the content file, then Base64-encode the hash. That value is the checksum.
It turns out all three headers have to be correct, otherwise the server rejects the request with SignatureDoesNotMatch.
What the website does is calculate the checksum and file size on the client side, then the server recalculates them to make sure everything matches. The problem is that you can calculate those values yourself even if the website never does it for you. The pre-signed Amazon S3 upload URL also stays valid for 300 seconds, which gave me enough time to calculate the checksum and send my own PUT request using the same URL.
Even though this didn't lead to RCE, an attacker can still bypass the file type restrictions and upload arbitrary files. If there are no server-side file size limits, they could also upload very large files (GBs), increasing storage costs and consuming bandwidth.
So when I was writing the report, I found out the subdomain was actually out of scope, i was sad for a moment, then I said to myself that I had learned a lot from testing this upload form, so it was still worth it. If I had checked the out-of-scope domains first, I probably wouldn't have tested it at all, and I would have missed learning all of this.