mass-assignment-anti-pattern

mass-assignment-anti-pattern

Security anti-pattern for mass assignment vulnerabilities (CWE-915). Use when generating or reviewing code that creates or updates objects from user input, form handling, or API request processing. Detects uncontrolled property binding enabling privilege escalation.

2звезд
1форков
Обновлено 1/22/2026
SKILL.md
readonlyread-only
name
"mass-assignment-anti-pattern"
description

"Security anti-pattern for mass assignment vulnerabilities (CWE-915). Use when generating or reviewing code that creates or updates objects from user input, form handling, or API request processing. Detects uncontrolled property binding enabling privilege escalation."

Mass Assignment Anti-Pattern

Severity: High

Summary

Mass assignment (also known as "autobinding") is a vulnerability that occurs when a web framework automatically binds incoming HTTP request parameters to variables or objects in the application's code. This is a convenient feature, but it becomes a vulnerability when an attacker can inject and set properties they are not supposed to control. The most common example is an attacker submitting a request with a field like "isAdmin": true and having the application blindly save it, escalating their privileges.

The Anti-Pattern

The anti-pattern is directly using a dictionary of user-provided data to create or update a database model without first filtering for allowed properties.

BAD Code Example

# VULNERABLE: The incoming request data is used directly to update the user model.
from flask import request
from db import User, session

@app.route("/api/users/me", methods=["POST"])
def update_profile():
    # Assume user is already authenticated.
    user = get_current_user()

    # Attacker crafts a JSON body:
    # {
    #   "email": "new.email@example.com",
    #   "is_admin": true
    # }
    request_data = request.get_json()

    # Many ORMs allow updating an object from a dictionary.
    # If the User model has an `is_admin` property, it will be updated here.
    for key, value in request_data.items():
        setattr(user, key, value) # Direct, unsafe assignment.

    session.commit()
    return {"message": "Profile updated."}

# The attacker has just made themselves an administrator.

GOOD Code Example

# SECURE: Use a Data Transfer Object (DTO) or an explicit allowlist to control which fields can be updated.
from flask import request
from db import User, session

# Option 1: Use an allowlist of fields.
ALLOWED_UPDATE_FIELDS = {"email", "first_name", "last_name"}

@app.route("/api/users/me", methods=["POST"])
def update_profile_allowlist():
    user = get_current_user()
    request_data = request.get_json()

    for key, value in request_data.items():
        # Only update the attribute if it's in our explicit allowlist.
        if key in ALLOWED_UPDATE_FIELDS:
            setattr(user, key, value)

    session.commit()
    return {"message": "Profile updated."}


# Option 2 (Better): Use a DTO or schema to define and validate the input.
from pydantic import BaseModel, EmailStr

class UserUpdateDTO(BaseModel):
    # This class defines the *only* fields that can be submitted.
    # The `is_admin` field is not here, so it can't be set by the user.
    email: EmailStr
    first_name: str
    last_name: str

@app.route("/api/users/me/dto", methods=["POST"])
def update_profile_dto():
    user = get_current_user()
    try:
        # Pydantic will raise a validation error if extra fields like `is_admin` are present.
        update_data = UserUpdateDTO(**request.get_json())
    except ValidationError as e:
        return {"error": str(e)}, 400

    user.email = update_data.email
    user.first_name = update_data.first_name
    user.last_name = update_data.last_name
    session.commit()
    return {"message": "Profile updated."}

Detection

  • Review update/create logic: Look for any code that takes a user-provided dictionary or object (request.body, params, etc.) and uses it to directly populate a model (e.g., user.update(params), new User(params)).
  • Check for "allowlists" vs. "blocklists": Code that tries to remove bad keys (a blocklist, e.g., del params['is_admin']) is insecure. A new sensitive property could be added to the model later and forgotten in the blocklist. Secure code uses an allowlist to only accept known-good keys.
  • Test API endpoints: Send requests to POST or PUT endpoints with extra, unauthorized fields in the JSON body (e.g., is_admin, role, account_balance) and see if the values are reflected in the API's response or the database.

Prevention

  • [ ] Use an allowlist approach: Never use a blocklist to filter incoming data. Always use an allowlist of properties that are permitted to be set by the user.
  • [ ] Use Data Transfer Objects (DTOs) or dedicated input schemas to strictly define the expected request body. This is the most robust solution.
  • [ ] Set sensitive properties explicitly in your code, outside of any mass assignment operation (e.g., new_user.is_admin = False).
  • [ ] Be aware of framework features: Some frameworks have built-in protections against mass assignment. Understand how to use them correctly.

Related Security Patterns & Anti-Patterns

References

You Might Also Like

Related Skills

coding-agent

coding-agent

179Kdev-codegen

Run Codex CLI, Claude Code, OpenCode, or Pi Coding Agent via background process for programmatic control.

add-uint-support

add-uint-support

97Kdev-codegen

Add unsigned integer (uint) type support to PyTorch operators by updating AT_DISPATCH macros. Use when adding support for uint16, uint32, uint64 types to operators, kernels, or when user mentions enabling unsigned types, barebones unsigned types, or uint support.

at-dispatch-v2

at-dispatch-v2

97Kdev-codegen

Convert PyTorch AT_DISPATCH macros to AT_DISPATCH_V2 format in ATen C++ code. Use when porting AT_DISPATCH_ALL_TYPES_AND*, AT_DISPATCH_FLOATING_TYPES*, or other dispatch macros to the new v2 API. For ATen kernel files, CUDA kernels, and native operator implementations.

skill-writer

skill-writer

97Kdev-codegen

Guide users through creating Agent Skills for Claude Code. Use when the user wants to create, write, author, or design a new Skill, or needs help with SKILL.md files, frontmatter, or skill structure.

Implements JavaScript classes in C++ using JavaScriptCore. Use when creating new JS classes with C++ bindings, prototypes, or constructors.

Creates JavaScript classes using Bun's Zig bindings generator (.classes.ts). Use when implementing new JS APIs in Zig with JSC integration.