DEV Community

Cover image for Python’s Private Variables Aren't Private: An AppSec Reality Check
Michael Oladele
Michael Oladele

Posted on

Python’s Private Variables Aren't Private: An AppSec Reality Check

Coming to Python from Java or C++? You might have a dangerous assumption about data encapsulation.

Look at this typical snippet used for "secure" state management:

class BankAccount:
    def __init__(self):
        self._balance = 1000
    @property
    def balance(self):
        return self._balance
    def withdraw(self, amount):
        if amount <= 0 or amount > self._balance:
            raise ValueError("Invalid operation") 
        self._balance -= amount
Enter fullscreen mode Exit fullscreen mode

It looks clean. We have a protected attribute (_balance) and validation logic. But from an AppSec view, this is an illusion.

The "Consenting Adults" Trap.

In Python, a single underscore is just a convention. It relies entirely on the honor system. The runtime environment does nothing to stop external scripts from bypassing your validation logic completely:

account = BankAccount()
account._balance = -999999 # Valid Python. Zero errors.

Enter fullscreen mode Exit fullscreen mode

What about Double Underscores (__)?

Switching to self.__balance triggers Name Mangling. While it throws an AttributeError if accessed directly, it offers zero true security. Anyone can easily bypass it:

account._BankAccount__balance = -999999 # Bypasses mangling
Enter fullscreen mode Exit fullscreen mode

The AppSec Takeaway: Syntax ≠ Security

We cannot rely on language syntax to safeguard application states. If an attacker exploits an upstream flaw—like Insecure Deserialization or unsafe reflection—they can overwrite these internal variables directly.

To enforce true data integrity in Python, build defensively:

  1. Use True Immutability: Deploy dataclasses with frozen=True to block runtime modifications.

  2. Server-Side Zero-Trust: Never trust local object states as your absolute source of truth. Always validate transactions against a secure database ledger.

  3. Automate Checks (SAST): Use tools like bandit or pylint in your CI/CD pipelines to flag external modifications of protected properties.

Code conventions keep repositories clean. Architectural controls keep applications secure.

How do you handle internal validation in your services? Let’s discuss below!

Top comments (0)