How a Second-Order IDOR Lets You Delete Other Users’ Posts, Profile Picture, and Cover Photo

Senior Student of Computer Science | 21 y/o Web Application Pentester My HackerOne Profile: https://hackerone.com/amir_shah
Hey Geeks,
It was a cool bug, so let’s skip the formalities and dive straight in.
So, the target was a social media application, pretty standard stuff. Users could upload profile pictures, cover photos, and post images. For obvious confidentiality reasons, I can’t mention its name.
While testing it, I had already come across a few IDOR vulnerabilities, things like deleting other users’ reviews or removing their “follows” just by swapping a UUID with someone else’s. (If you’re not familiar with IDOR, I’ve explained them in detail in a couple of my earlier blogs — go check those out.)
But when I tried to delete another user’s post this time, the app actually threw a 403 Forbidden error. So I thought, “Okay… maybe they finally fixed it.”
Still, something felt off. I opened my profile panel, changed my profile picture, and started watching the requests closely in my proxy. I noticed when I change my profile picture, two requests were sent which caught my eye:
The first one uploaded the image to the server and returned an ID (probably a MongoDB ObjectID.)
The second one was a WebSocket request that used that ID to set the image on my profile.
Here are the requests:


As you can see, the image is being uploaded to your profile using the storageId parameter in the WebSocket request.
So, I decided to change that to another user’s storageId.
But how could we obtain other users’ storage IDs?
It was actually easy — if we navigated to users’ public profiles, we could easily get their storageId.
I got one, and initiated the process again. After replacing my own storage ID with someone else’s, I got their profile picture (haha, funny, right? No?). You might say, “Okay, that’s not really a bug,” — and you’d be right…
But then, when I deleted my profile picture, I noticed something surprising — the victim’s profile picture was deleted as well! :)
I was like, Wait, what?!
Then I realized the same logic applied to the cover photo too. We could change to another user’s storage ID, and when we deleted our own cover photo, the victim’s cover photo would get deleted too.
What makes the vulnerability more severe is that I was able to delete a post’s image using this logic. I’d open the feed and, in the response, see post details ( likes, comments, and so on ) and there was a storageId that referenced the post image. I grabbed that storageId, set it as the image in my profile, then deleted it — and guess what? The post lost its image. hehe :))
Root Cause
I think the root cause is simple: when an image is uploaded, a field is created in the database that holds the storageId. If we replace that field in our profile with someone else’s storageId, both accounts end up pointing to the same file in the database. So when we delete “our” profile picture, the app deletes the file by storageId — but it never verifies that the storageId actually belongs to the account performing the delete. The result: the image is gone for everyone, and we can delete the victim’s profile picture and cover photo too.
Fix?: ( Not Yet )
I reported the bug and it was patched within a few hours, but the fix was loose. The patch only checked whether the image was a cover photo, so you couldn’t set a storageId as your cover photo. I thought “hmm, interesting,” and then bypassed it. I changed my cover photo and set the storageId of someone else’s profile picture; when I deleted my cover, the victim’s profile picture was deleted. I also tried the reverse: set my profile picture to another user’s cover storageId, then deleted my profile picture — the other user’s cover was removed.
Fix? ( Not Yet again )
Then the profile and cover photo features changed (their logic and request flow were completely redesigned). There was no second request anymore; everything was handled in a single request!
Butttt!!!
I discovered that users could still edit their posts (both captions and images). So, I created a post, clicked on “Edit,” deleted its image, and intercepted the request. You might think, “Did you change the storageId there?” — but no, man, it didn’t work. Here’s what that request looked like:

The bug is Second-Order IDOR, so everything had to work secondly. I played with the parameters — changed mustDelete to false, isNew to true, and replaced the storageId with someone else’s post image, profile picture, or cover photo storageId (yes, the flow was different, but they all still used storageId).
I noticed that I could edit my own post and add someone else’s profile picture to it. Now you’re right :) — I deleted my post and observed that the victim’s profile picture was deleted as well! The same worked for cover photos, post images, or basically any image uploaded elsewhere.
I hope you enjoyed my write-up! I think it was a pretty cool bug.
Have a good day!
Be Happy, Be Nice! ✌️
My X: x.com/ali_4fg
My LinkedIn: linkedin.com/in/ali-hussainzada



