Post

Been testing the IDOR trick where you wrap the identifier in an array, in Node JS. You are 123, victim is 124. {"user_id": [124, 123]} The ORM doesn't pick the first element. Sequelize and Mongoose turn it into WHERE id IN (124, 123) and can write both rows.

This only works if the middleware checks whether your ID is in the array. These pass: [].concat(id).includes(123) [].concat(id).some(x => x == 123) Strict == and === both reject [124,123]. So does Number().

One that surprised me, though it's already known: parseInt([123,124]) === 123 is true. The array becomes the string "123,124" and parseInt stops at the comma. So put your own ID first to get past a parseInt check.

Then it's up to the ORM: Sequelize -> IN (124,123), both rows written Mongoose -> implicit $in, both rows written TypeORM -> throws RangeError Knex -> throws on bind Prisma -> throws, Expected Int, provided (Int, Int)

You don't need a JSON body either. Duplicate params gave me an array in every Express config I tried: user_id=124&user_id=123 -> ["124","123"] They arrive as strings, so includes(123) fails, but some(x => x == 123) still passes and Sequelize still fires: IN ('124','123')

You always write to your own row too. [124] alone would hit only the victim, but the middleware rejects it because your ID isn't there. To get past the check you have to include yourself, and the ORM writes to everything in the list.

0 reposts0 likes

On the read path, findOne returns your own row whatever the order. The issue is on findAll/find, which returns both. Mongo operators like {"$in":[124]} can hit only the victim, but fail every middleware check I tested. Only reachable where the field isn't inspected.