Web API Security Champion Part III: Broken Object Property Level Authorization (OWASP TOP 10)

May 26, 2024

This article is a part of Web API Security Champion series focused on API security vulnerabilities presented in a practical manner.

Broken Object Property Level Authorization

Description

Broken Object Property Level Authorization is an API vulnerability that allows attackers to bypass access control mechanisms and manipulate individual properties of an object without proper permissions. This vulnerability occurs when the API does not adequately enforce authorization checks at the property level, enabling unauthorized users to modify sensitive fields within an object. While similar to Broken Object Level Authorization, this vulnerability focuses on specific properties within an object rather than the entire object itself. This vulnerability is also known as a “Mass Assignment” vulnerability.

In my career, I have observed a number of Broken Object Property Level Authorization vulnerabilities. These issues often arise when the same data model is utilised for various CRUD operations without granular authorization checks implemented, assuming that property-level access do not require the same scrutiny as object-level operations. This vulnerability is is listed among the OWASP TOP 10 API Security Risks.

Impact

An attacker with knowledge of an object and its properties can potentially update, modify, or delete information within that object. Depending on the specific property and its role within the application, this could lead to data breaches, unauthorized transactions, or other significant security impacts. For example, modifying a user’s role property to escalate privileges or altering transaction amounts in a financial application may have severe consequences.

A two examples of this vulnerability reported via HackerOne are listed below:


Case Study — Damn Vulnerable RESTaurant API

To illustrate the vulnerability, I will use my open-source project — Damn Vulnerable RESTaurant API. This project is available on my GitHub:

Damn Vulnerable RESTaurant is an intentionally vulnerable web application designed for developers to explore and fix security issues. It is an excellent resource for developers, ethical hackers, and security engineers.

Vulnerability Description

The Broken Object Property Level Authorization vulnerability is present in the PUT /profile API endpoint. This endpoint handles profile update operations. User can update various fields specified by the schema. Unfortunately, the User schema includes role field which might be also updated by the user. As a result, a regular customer user may perform privilege escalation by updating role field to Employee or Chef!

Here is the vulnerable API endpoint implementation in FastAPI:

from apis.auth.schemas import User as UserSchema

...

@router.put("/profile", response_model=UserRead, status_code=status.HTTP_200_OK)
def update_current_user_details(
    user: UserSchema,
    current_user: Annotated[User, Depends(get_current_user)],
    db: Session = Depends(get_db),
):
    db_user = update_user(db, user.username, user)

    return current_user

The User class with role field is presented below:

class User(BaseModel):
    username: str
    first_name: Union[str, None] = None
    last_name: Union[str, None] = None
    phone_number: Union[str, None] = None
    role: Union[str, None] = None

Broken Object Property Level Authorization Proof of Concept

Exploiting this vulnerability is straightforward. For example, the following curl HTTP request can be sent to change the role of the current user to perform privilege escalation to restaurant’s employee:

curl -X 'PUT' \
  'http://localhost:8080/profile' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNaWtlIiwiZXhwIjoxNzE2NzUxNjYwfQ.8khfY1H_2VLZPNuxptkEdOstuJlpME6ZAJNGnKZKFd0' \
  -H 'Content-Type: application/json' \
  -d '{
  "username": "Mike",
  "role": "Employee"
}'

HTTP response body shown below presents a role updated to Employee succesfully:

{
  "username": "Mike",
  "first_name": "Mike",
  "last_name": "",
  "phone_number": "",
  "role": "Employee"
}

As a result, Mike was able to perform vertical privilege escalation and gain access to API endpoints reserved for employees that he previously couldn’t access.

Broken Object Property Level Authorization Fix

To fix this vulnerability, it’s recommended to implement a new schema UserUpdate which defines what fields can be updated by the user. In this way, users won’t be able to update fields that are not included in the schema. Below snippet presents the new UserUpdate schema which doesn’t include role field.

class UserUpdate(BaseModel):
    username: str
    first_name: Union[str, None] = None
    last_name: Union[str, None] = None
    phone_number: Union[str, None] = None

Now, UserUpdate schema can be utilised in update_current_user_details function as presented below:

from apis.auth.schemas import UserUpdate

...

@router.put("/profile", response_model=UserRead, status_code=status.HTTP_200_OK)
def update_current_user_details(
    user: UserUpdate,
    current_user: Annotated[User, Depends(get_current_user)],
    db: Session = Depends(get_db),
):
    db_user = update_user(db, user.username, user)

    return current_user

The HTTP request described in the previous section no longer sets the user’s role to the provided value as the role is not listed in the UserUpdate schema. After the fix, the HTTP endpoint returns the user’s role without updating it in the response body.

Broken Object Property Level Authorization Recommendations

To prevent such vulnerabilities, I recommend the following:

  • Deny access by default: Follow the principle of least privilege and only grant permissions necessary for specific roles.
  • Use schemas/DTOs based validation mechanism with different schemas dedicated for each CRUD operation to make sure that only specified fields can be accessed or modified.
  • Implement granular authorization checks: Ensure authorization is checked at both the object and property levels.
  • Keep data structures to the bare minimum, according to the business/functional requirements for the endpoint.
  • Use unpredictable identifiers: Prevent brute-force attempts by using GUIDs or other non-sequential identifiers.
  • Write unit tests for property-level access: Ensure unauthorized access attempts are covered by unit tests.
  • Perform code reviews: Regularly review code to identify potential security issues.

A recommended unit test to ensure unauthorized users cannot modify user’s role:

def test_update_role_by_customer_ignores_role_returns_200(test_db, customer_client):
    data = {
        "username": "customer",
        "role": "Employee",
    }   
    response = customer_client.put("/profile", json=data)

    assert response.status_code == 200
    assert db_customer.role == UserRole.CUSTOMER

Broken Object Property Level Authorization Automated Detection

Detecting such vulnerability manually or through code reviews can be effective. Additionally, Static Application Security Testing and Dynamic Application Security Testing tools can help automate the detection process but it may require a custom rules/workflows adjusted to the utilised technology. At the time of writing this article, the detection of such vulnerabilities by automated tools is challenging and may not provide a satisfying results without a proper project-specific adjustments.

In the first article of this series, I presented how to develop a custom Semgrep rool to detect project-specific vulnerable patterns — Web API Security Champion II: Broken Object Level Authorization.


Summary

In this article, I presented the Broken Object Property Level Authorization vulnerability with practical example, fix, and recommendations for developers and security engineers. This insight into detecting and addressing such vulnerabilities will help you build more secure APIs.

References


Interesting Article?

Join DevSec Selection!

DevSec Selection is a bi-weekly Newsletter with the latest outstanding articles related with DevSecOps and application security.


Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments