Weakness reference
CWE-665

Improper Initialization

Improper initialization occurs when a software component fails to set up a resource—such as a variable, array, object, or connection—to a known safe state…

01Summary

Improper initialization occurs when a software component fails to set up a resource—such as a variable, array, object, or connection—to a known safe state before use. This can leave the resource containing garbage data, default values, or unintended state, leading to unpredictable behavior or security flaws downstream. Even a single uninitialized field can become an attack surface if an attacker can influence how that state is later used.

02How It Happens

Developers often assume that variables, objects, or data structures start in a safe or predictable state, but many languages and environments do not guarantee this. In some cases, memory may retain data from previous operations; in others, default values may be unsafe (e.g., a permission flag defaulting to "allow" instead of "deny"). Additionally, complex objects with many fields may have some fields intentionally left unset, but if the code later reads those fields without checking, it may operate on stale or malicious data. Race conditions during initialization can also leave resources partially set up, and error paths that skip initialization steps can cause downstream code to work with incomplete state.

03Real-World Impact

Uninitialized state can lead to information disclosure (reading stale data from memory), privilege escalation (if a permission or role field is not properly set), authentication bypass (if a verification flag is not initialized to a secure default), or denial of service (if uninitialized pointers or sizes cause crashes). In web applications, this often manifests as session state leaks, incorrect access control decisions, or unexpected behavior in multi-threaded or asynchronous contexts where initialization order is not guaranteed.

04Vulnerable & Fixed Patterns

Vulnerable pattern
class UserSession:
    def __init__(self, user_id):
        self.user_id = user_id
        # is_admin is never initialized
        # self.is_admin is left undefined

    def grant_access(self, resource):
        # Later code assumes is_admin exists and has a safe default
        if self.is_admin:  # AttributeError or uses stale value
            return True
        return False

session = UserSession(123)
print(session.grant_access("admin_panel"))

Why it's vulnerable:
The is_admin attribute is never initialized, so accessing it later either raises an error or, in some contexts, may read uninitialized memory or a leftover value from a previous object.

Fixed pattern
class UserSession:
    def __init__(self, user_id):
        self.user_id = user_id
        # Explicitly initialize all fields to safe defaults
        self.is_admin = False
        self.is_authenticated = False
        self.permissions = set()

    def grant_access(self, resource):
        if self.is_admin:
            return True
        return False

session = UserSession(123)
print(session.grant_access("admin_panel"))  # Safely returns False
Vulnerable pattern
<?php
class UserAccount {
    public $user_id;
    public $role;
    // $role is declared but never initialized in __construct

    public function __construct($user_id) {
        $this->user_id = $user_id;
        // Missing: $this->role = 'guest';
    }

    public function can_delete_user() {
        // Later code assumes $role is set
        return $this->role === 'admin';
    }
}

$account = new UserAccount(42);
var_dump($account->can_delete_user());  // Undefined property warning or unexpected result
?>

Why it's vulnerable:
The $role property is never set in the constructor, so it remains undefined. Later code that checks this property may behave unpredictably or trigger warnings that mask the real issue.

Fixed pattern
<?php
class UserAccount {
    public $user_id;
    public $role;

    public function __construct($user_id) {
        $this->user_id = $user_id;
        // Explicitly initialize to a safe default
        $this->role = 'guest';
    }

    public function can_delete_user() {
        return $this->role === 'admin';
    }
}

$account = new UserAccount(42);
var_dump($account->can_delete_user());  // Safely returns false
?>

05Prevention Checklist

Initialize all variables and object fields explicitly
in constructors, factory methods, or at declaration time; never rely on implicit defaults or assume memory is zeroed.
Use allowlists and safe defaults
for security-critical fields (e.g., permissions default to "deny," not "allow"; roles default to "guest," not "admin").
Validate initialization state
before use—add assertions or guards that confirm required fields are set before they are read.
Review error paths and exception handlers
to ensure that initialization steps are not skipped if an error occurs partway through setup.
Use static analysis or linters
to detect uninitialized variable access and missing field assignments.
In multi-threaded or async code, use thread-safe initialization patterns
(e.g., double-checked locking, atomic flags) to prevent race conditions during setup.

06Signs You May Already Be Affected

Look for unexpected AttributeError, TypeError, or "undefined property" warnings in logs, especially in security-sensitive code paths. Check for inconsistent behavior in access control decisions, session handling, or permission checks—particularly if behavior differs between the first request and subsequent requests, or between single-threaded and multi-threaded execution. Review recent code changes for new object types or refactored constructors where fields may have been added but not initialized.

07Related Recent Vulnerabilities