How Python Stops Prototype Pollution in Web APIs

Prototype pollution is primarily known as a high-severity JavaScript vulnerability, but Python web APIs can face analogous threats through dynamic attribute manipulation, mass assignment, and object pollution. While Python does not use prototypal inheritance, malicious JSON payloads can attempt to alter internal object attributes or class definitions if applications dynamically assign keys to objects without validation. Python neutralizes these risks through an immutable built-in type hierarchy, strict namespace controls, and robust deserialization practices implemented by modern web frameworks.

Prototypal vs. Class-Based Inheritance

In JavaScript, objects inherit properties directly from prototypes, meaning modifying Object.prototype alters every object in the runtime environment. Python relies on a strict, class-based inheritance model governed by the Method Resolution Order (MRO).

Instances inherit behavior from classes, but objects do not share a single dynamic prototype object that can be globally modified at runtime through standard assignment. Attempting to assign an attribute to a base object will not automatically cascade across unrelated instances, inherently preventing direct prototype pollution.

Immutability of Built-in Classes

In Python, built-in types such as object, dict, list, and str are implemented in C and possess immutable namespaces:

obj = object()
obj.polluted = True  # Raises: AttributeError: 'object' object has no attribute 'polluted'

object.polluted = True  # Raises: TypeError: cannot set 'polluted' attribute of immutable type 'object'

Because an attacker cannot inject properties into base built-ins, system-wide behavior cannot be hijacked via native base classes.

Protection of Special Attributes

Python objects use dunder (double underscore) attributes to manage metadata, such as __class__, __dict__, and __mro__. While attackers often target these attributes to achieve Remote Code Execution (RCE) in Server-Side Template Injection (SSTI) or deserialization exploits, standard Python operations limit write access to these internals:

Mitigating Dynamic Attribute Manipulation with __slots__

To explicitly block attribute injection on custom instances, Python provides __slots__. By defining __slots__, a class skips the creation of a dynamic __dict__, permitting only a predefined set of attributes:

class SecureProfile:
    __slots__ = ('username', 'email')

profile = SecureProfile()
profile.username = "alice"
profile.admin = True  # Raises: AttributeError: 'SecureProfile' object has no attribute 'admin'

Using __slots__ ensures that arbitrary properties supplied in an API payload cannot be attached to internal objects.

Framework-Level Payload Validation

Python web APIs avoid attribute manipulation largely through structural separation of incoming data from business logic objects.

Modern frameworks like FastAPI, Django REST Framework, and libraries like Pydantic and Marshmallow enforce strict data validation: