๐ What Is It?
Broken Object Property Level Authorization occurs when APIs expose too many object properties or allow modification of restricted properties. This manifests as Excessive Data Exposure (seeing sensitive fields) and Mass Assignment (modifying restricted fields).
API03
OWASP Rank
Object
Property Level
2 Types
Exposure+Assignment
โ ๏ธ Common Exploits
- Excessive Data Exposure: API returns password_hash, SSN, salary in user profile
- Mass Assignment: Set is_admin=true in profile update request
- Price Manipulation: Change product price or discount in order request
- Role Escalation: Modify role field to gain admin privileges
- Status Manipulation: Change order status from pending to approved
- Hidden Fields: Sensitive fields exposed in API but hidden in UI
๐ด Attack Flow
1. User requests profile: GET /api/users/me
โ
2. API returns ALL fields including sensitive ones
โ
3. Attacker observes is_admin: false
โ
4. Sends PUT with is_admin: true
โ
5. BREACH: Admin access granted!
โ
2. API returns ALL fields including sensitive ones
โ
3. Attacker observes is_admin: false
โ
4. Sends PUT with is_admin: true
โ
5. BREACH: Admin access granted!
โ Vulnerable Code
// Bad: Returns entire model with sensitive fields
@app.route('/api/users/me')
@login_required
def get_profile():
# Returns ALL fields including sensitive ones!
return jsonify(current_user)
// Response exposes:
{
"id": 123,
"name": "John Doe",
"password_hash": "$2b$12$...", โ Shouldn't expose!
"is_admin": false, โ Shouldn't expose!
"salary": 85000, โ Shouldn't expose!
"ssn": "123-45-6789" โ Shouldn't expose!
}
// Bad: Mass assignment vulnerability
@app.route('/api/users/<user_id>', methods=['PUT'])
@login_required
def update_profile(user_id):
user = User.query.get(user_id)
# Accepts ALL fields from request!
user.update(**request.json) โ DANGEROUS!
db.session.commit()
return jsonify(user)
โ Secure Code
// Good: Whitelist fields to return
@app.route('/api/users/me')
@login_required
def get_profile():
# Only return safe fields
return jsonify({
'id': current_user.id,
'name': current_user.name,
'email': current_user.email,
'created_at': current_user.created_at
})
// Good: Use DTO/serializer for responses
class UserSerializer:
safe_fields = ['id', 'name', 'email']
def serialize(user):
return {field: getattr(user, field)
for field in safe_fields}
// Good: Whitelist fields for updates
@app.route('/api/users/<user_id>', methods=['PUT'])
@login_required
def update_profile(user_id):
user = User.query.get_or_404(user_id)
# Only allow specific fields to be updated
allowed_fields = ['name', 'email', 'bio']
for field in allowed_fields:
if field in request.json:
setattr(user, field, request.json[field])
db.session.commit()
return jsonify(UserSerializer.serialize(user))
โ Prevention Checklist
- Use DTOs/serializers to control exposed fields
- Whitelist fields for API responses
- Whitelist fields accepted in updates
- Never return entire database models
- Remove sensitive fields: passwords, tokens, keys
- Implement role-based field visibility
- Validate field permissions on every request
- Use separate models for input/output
- Test with different user roles
- Code review for property exposure
๐ Detection & Tools
Testing Tools:
Burp Suite
OWASP ZAP
Postman
curl
Fiddler
Prevention Libraries:
Marshmallow
Django REST Framework
Pydantic
Jackson (Java)
Active Model Serializers
How to Test:
- Examine all API response fields for sensitive data
- Try adding admin/privileged fields in PUT/PATCH
- Test mass assignment with unexpected fields
- Compare database schema vs API response
- Check for password hashes, tokens in responses
๐ Real-World Breaches
- LinkedIn (2012): Mass assignment allowed users to modify any profile field
- GitHub (2012): Mass assignment vulnerability allowed public key injection
- Ruby on Rails Apps: Mass assignment vulnerabilities in early Rails versions
- E-commerce Platforms: Price manipulation via mass assignment in checkout APIs
- Banking APIs: Excessive data exposure revealing account balances and PINs
๐ Quick Tips
- DO NOT return entire database models
- DO NOT accept all request fields blindly
- DO NOT expose admin/internal fields
- DO use serializers/DTOs for responses
- DO whitelist allowed update fields
- DO implement field-level permissions
๐ Compliance
Related Standards:
- GDPR Art. 5 - Data Minimization
- PCI-DSS Requirement 3.3
- HIPAA ยง164.514 - De-identification
- SOC 2 CC6.1
- ISO 27001 A.9.4
- CCPA Data Minimization