BugForge - Daily - Sokudo
Daily - Sokudo
Vulnerabilities Covered
Summary
Sokudo's profile page saves changes through a hardened PUT /v2/profile endpoint that ignores unexpected properties, so injecting a role field there had no effect. The application, however, still exposes the legacy non-versioned PUT /api/profile route, which binds the incoming JSON body directly onto the user record without an allow-list. After registering an ordinary account, the admin-only listing at GET /api/admin/users returned 403 Forbidden. By downgrading the profile update from /v2/profile to the unversioned /api/profile and appending "role":"admin" to the otherwise legitimate payload, the account was silently promoted to administrator. Re-requesting /api/admin/users then succeeded and returned the flag. This demonstrates how a mass assignment (auto-binding) flaw on a forgotten legacy API version collapses the entire authorization model, letting a self-service account grant itself administrative privileges.
Reference
Account Creation and Baseline Review
A new user account was registered while intercepting both the request and response. The goal at this stage was to understand the registration flow and to spot any role, privilege, or identifier fields that shape later authorization decisions. The response confirmed the account was created with a non-privileged role of user, establishing the baseline privilege level to escalate from.

Mapping the Admin Surface
With a session established, the API was explored for administrative functionality. The /api/admin/users route stood out as an obvious target, an admin-only listing of every registered account. Requesting it as the freshly registered user returned 403 Forbidden, confirming the endpoint exists and is guarded by a role check rather than being hidden entirely.
That single response is a strong signal: the server clearly distinguishes admin from user, so the next question is whether that role is something the account holder can influence.

Inspecting the Profile Update
The profile page issues a PUT /v2/profile request to save changes. Capturing a normal save showed the client submits the full profile object, harmless presentation fields such as full_name, bio, website, and keyboard. The interesting test is whether the server will also accept fields the UI never sends, in particular the role attribute observed during registration.
{"full_name":"Zwarts","bio":"","website":"","keyboard":""}
Appending "role":"admin" to this v2 request had no effect, the account remained a user and /api/admin/users still returned 403. The versioned endpoint clearly binds against an allow-list and quietly discards the injected field.
Downgrading to the Legacy Endpoint
Since the v2 handler was hardened, the next question was whether an older, unhardened version of the same route still existed. Swapping the /v2/ prefix for the non-versioned /api/ path and targeting PUT /api/profile produced a very different result. This legacy handler binds the request body straight onto the user record, so the same "role":"admin" payload that v2 ignored was accepted and persisted here, a textbook mass assignment (auto-binding) flaw left behind on a forgotten API version.
{"full_name":"Zwarts","bio":"","website":"","keyboard":"","role":"admin"}

Reading the Flag
With the account now promoted to admin, the previously forbidden listing was requested again. This time GET /api/admin/users returned 200 OK and the full user collection, which contained the flag, confirming a complete privilege escalation from a self-registered account.

Impact
- Full vertical privilege escalation from a self-registered
usertoadmin - Unauthorized access to the administrative user listing and every account’s details
- Complete bypass of the application’s role-based access control model
- Any anonymous visitor can register and grant themselves administrator privileges by downgrading to the legacy endpoint
- A hardened
v2endpoint is fully undermined by an older, unmaintained/api/profileroute still routed and reachable - The same auto-binding flaw likely exposes other protected attributes (e.g. account status, ownership, verification flags)
Vulnerability Classification
- OWASP Top 10: A01:2021 - Broken Access Control
- OWASP API Top 10: API3:2023 - Broken Object Property Level Authorization (Mass Assignment), API6:2023 - Unrestricted Access to Sensitive Business Flows
- Vulnerability Type: Mass Assignment / Auto-Binding leading to Privilege Escalation
- Attack Surface: REST API endpoint (
PUT /api/profile) that binds client input directly onto the user model - CWE: CWE-915 - Improperly Controlled Modification of Dynamically-Determined Object Attributes, CWE-269 - Improper Privilege Management
Root Cause
The mass assignment protection was only ever applied to the current PUT /v2/profile handler, which binds against an allow-list and discards unexpected fields. The older, non-versioned PUT /api/profile handler was left routed and reachable, and it deserializes the request body and binds every field onto the persisted user record without any allow-list of client-editable properties. It never separates presentation attributes (full_name, bio, website, keyboard) from security-sensitive ones (role). Because the authorization decision on /api/admin/users trusts the stored role value, and that value is writable through the forgotten legacy endpoint, a user can grant themselves the exact privilege the access control check is meant to enforce. The fix on v2 gave a false sense of security while the vulnerable prior version remained live, a classic API versioning / shadow-endpoint gap.
Remediation
- Bind requests to an explicit allow-list of client-editable fields (a dedicated DTO/schema), never directly onto the persistence model
- Decommission superseded API versions once clients migrate, and inventory all routed endpoints so a hardened
v2is not undercut by a still-livev1/unversioned route - Apply the same authorization and binding controls uniformly across every version of an endpoint
- Treat privilege fields such as
roleas server-controlled only, mutable exclusively through a separate, authorized administrative workflow - Reject or ignore unexpected properties in request bodies rather than silently persisting them
- Enforce least privilege so role changes require an already-privileged actor and are audited
- Add integration tests that assert protected attributes cannot be modified through user-facing endpoints
- Log and alert on role or privilege changes to detect escalation attempts