SecureBlockLog inStart a pentest
Vulnerability Repository
HighAPI

Broken Object Property Level Authorization

APIs that fail to restrict which object properties users may read or write allow privilege escalation by modifying internal fields in update requests.

CVSS 8.1CWE CWE-285OWASP A03:2023 — Broken Object Property Level Authorization

Description

Broken Object Property Level Authorization (BOPLA) is a class of access control failure where an API endpoint correctly verifies that a user may access a resource, but fails to verify which properties of that resource the user is permitted to read or write. This creates two distinct attack patterns: over-permission on write operations (mass assignment), where users inject properties into update requests that they should not be able to modify; and over-permission on read operations (excessive data exposure), where responses include sensitive fields the user should not see.

CWE-285 (Improper Authorization) applies because the authorization decision is incomplete—the API checks "can this user access this object?" but not "can this user modify this specific property?" OWASP API Security Project introduced BOPLA as A03 in the 2023 revision, combining what were previously separate mass assignment and excessive data exposure categories into a unified property-level authorization concept.

Mass assignment vulnerabilities are particularly common in frameworks that automatically bind request body parameters to model attributes (Rails, Laravel, Django, NestJS). Without explicit allowlisting of writeable fields, a user who adds "is_admin": true or "account_balance": 999999 to a profile update request may have those values persisted to the database.

How It Works

A normal user updates their profile name:

PATCH /api/v1/users/me HTTP/1.1
Host: api.example.com
Authorization: Bearer <user_token>
Content-Type: application/json

{"name": "Alice Johnson"}

HTTP/1.1 200 OK
{"id": 12345, "name": "Alice Johnson", "is_admin": false}

The attacker adds privileged fields to the same request:

PATCH /api/v1/users/me HTTP/1.1
Host: api.example.com
Authorization: Bearer <user_token>
Content-Type: application/json

{
  "name": "Alice Johnson",
  "is_admin": true,
  "role": "superadmin",
  "account_balance": 99999,
  "email_verified": true
}

HTTP/1.1 200 OK
{"id": 12345, "name": "Alice Johnson", "is_admin": true}

If the server uses an ORM that mass-assigns request body parameters directly to the model without an explicit allowlist, the privileged fields are written to the database. The attacker has escalated to administrator without any authentication bypass.

In Rails, vulnerable code looks like:

# Vulnerable: mass assignment via strong parameters omission
def update
  @user.update(params[:user])  # All params accepted
end

# Fixed: explicit allowlist
def update
  @user.update(user_params)
end

def user_params
  params.require(:user).permit(:name, :email)  # Only name and email
end

Testers systematically add every field observed in API responses to update requests, observing whether the server accepts and persists them.

Impact

  • Privilege escalation — Users set is_admin, role, or permissions fields to gain unauthorized administrative access.
  • Financial fraud — Account balance, credit limit, or discount rate fields are modified to benefit the attacker.
  • Account verification bypass — Fields like email_verified, kyc_status, or subscription_tier are set to bypass business controls.
  • Data integrity violation — Modification of internal audit fields (created_at, last_modified_by) corrupts audit trails.
  • Sensitive data leakage — Read-side BOPLA exposes password hashes, internal IDs, and confidential flags to unauthorized users.

Detection

  1. Intercept a standard object update request (PATCH or PUT) in Burp Suite and add every field observed in the GET response for the same object, then submit and compare the response.
  2. Specifically test adding is_admin: true, role: "admin", account_tier: "enterprise", and similar privilege-related fields to update requests.
  3. Compare the response body fields to the request body fields—any fields in the response that were not in the request suggest server-side property access to audit on read.
  4. Test non-standard HTTP methods: some APIs use PUT (full replacement) rather than PATCH; test full-replacement payloads that include all observed fields.
  5. Compare the API behavior between different user roles by sending the same requests with standard user and admin tokens, noting which properties each role can write.

Remediation

Use explicit input allowlists. Define serializers or DTOs that enumerate only the properties users may write. Never pass raw request bodies to ORM update methods:

# Django REST Framework — write-specific serializer
class UserUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['name', 'email', 'phone']  # Writeable fields only
        read_only_fields = ['is_admin', 'role', 'account_balance']

Apply property-level authorization. For operations that require field-level access differences between roles, implement explicit authorization checks per field in the update handler.

Separate read and write schemas. Use different serializer classes for GET (read) and PATCH/PUT (write) operations. The read serializer may return more fields than the write serializer accepts.

Log and alert on unexpected fields. Detect potential BOPLA exploitation attempts by logging when requests include fields outside the expected schema and alerting on patterns.

Ready when you are
Scope a pentest in the next two minutes.
Start scoping