Skip to content

CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes

Overview

This vulnerability occurs when user input is used to modify object attributes or properties dynamically, allowing attackers to alter application behavior or access unauthorized data.

Related: Mass assignment (CWE-915) controls which properties can be modified. For ASP.NET applications, also see CWE-1174 which validates the values of properties that users are allowed to set.

OWASP Classification

A08:2025 - Software or Data Integrity Failures

Risk

High: Attackers can escalate privileges, bypass security controls, or corrupt data by manipulating object attributes at runtime.

Remediation Steps

Core principle: Never allow mass assignment of object attributes; bind/allowlist permitted fields and enforce invariants server-side.

Locate the dynamically-determined object attribute modification

  • Review the flaw details to identify the specific file, line number, and code pattern
  • Understand the data flow from source to sink: where user input influences object attributes
  • Identify the source: HTTP parameters, JSON input, form data, external configuration
  • Trace to the sink: setattr(), __dict__, obj[user_input] =, Object.defineProperty(), mass assignment
  • Determine risk: can attacker modify security-critical attributes (isAdmin, role, price, balance)

Restrict attribute modification to allowed properties (Primary Defense)

  • Use allowlist of permitted attributes: ALLOWED_ATTRS = {'name', 'email', 'phone'}
  • Validate attribute name before modification: if attr_name not in ALLOWED_ATTRS: raise ValueError
  • Reject unauthorized properties: Block attempts to set attributes not in allowlist
  • Never use user input directly as attribute name: Don't do setattr(obj, user_input, value)
  • Use explicit setters: Prefer obj.set_name(value) over setattr(obj, 'name', value)
  • Why this works: Attacker can only modify pre-approved, non-security-critical attributes

Validate and sanitize attribute names and values

  • Enforce strict type checks: Verify attribute values match expected type (string, int, boolean)
  • Apply length and format validation: Limit string length, validate email/phone formats
  • Sanitize values: Remove dangerous characters, encode special characters
  • Check attribute name format: Use regex to ensure attribute names are alphanumeric only
  • Reject special attributes: Block __class__, __dict__, __init__, constructor, prototype

Use safe APIs for object manipulation (Defense in Depth)

  • Prefer explicit setters/methods: Use obj.setName(), obj.setEmail() instead of dynamic assignment
  • Use immutable objects: Use frozen dataclasses, namedtuples, or read-only properties where possible
  • Avoid dynamic features with untrusted input: Don't use setattr, __dict__, eval, getattr with user input
  • Use frameworks with built-in protection: ORM allowlists (Django fields, Rails permit), schema validation
  • Implement property decorators: Use @property and explicit setters to control attribute access

Monitor and audit attribute changes

  • Log all dynamic attribute modifications with attribute name, value, and source
  • Alert on suspicious changes (attempts to modify security-critical attributes like isAdmin, role, permissions)
  • Track rejected modification attempts (blocked by allowlist)
  • Monitor for unusual patterns (bulk attribute changes, rapid modifications)
  • Audit security-sensitive object changes (user roles, permissions, pricing)

Test the attribute control fix thoroughly

  • Test with allowed attributes (should work: name, email, phone)
  • Test with forbidden attributes (should be rejected: isAdmin, role, __class__)
  • Test attribute injection: isAdmin=true, role=administrator, price=0
  • Test special Python/JavaScript attributes: __dict__, prototype, constructor
  • Verify legitimate functionality still works (profile updates, settings changes)
  • Re-scan with security scanner to confirm the issue is resolved

Common Vulnerable Patterns

  • Using user input to set object attributes directly
  • Allowing arbitrary property modification via APIs

Dynamic Attribute Assignment from User Input (Pseudocode)

# Dangerous: sets attribute from user input
setattr(obj, user_input, value)

Why this is vulnerable: Allowing user input to directly control which object attributes are modified enables attackers to set arbitrary properties including sensitive fields like is_admin, role, or password_hash, leading to privilege escalation, authentication bypass, or data corruption through mass assignment attacks.

Secure Patterns

Allowlist-Based Attribute Assignment (Pseudocode)

# Safe: use allowlist for attributes
allowed_attrs = {'name', 'email', 'phone'}
if user_input in allowed_attrs:
    setattr(obj, user_input, value)
else:
    raise SecurityError('Attribute not allowed')

Why this works:

  • Restricts attribute modification to pre-approved properties, preventing privilege escalation
  • Blocks attackers from modifying sensitive fields like is_admin, role, or password_hash
  • Prevents mass assignment vulnerabilities where attackers set unauthorized object properties
  • Ensures only intended user-modifiable fields can be changed via API or form submissions
  • Protects against prototype pollution in JavaScript and similar attribute manipulation attacks

Additional Resources