The vulnerability is a Time-of-Check-Time-of-Use (TOCTOU) race condition in virtualenv. An attacker with local access could create a symbolic link between the time virtualenv checks for the existence of a directory and the time it creates it. This would allow the attacker to control the location where directories for application data and locks are created, leading to potential cache poisoning, information disclosure, or denial of service.
The patch addresses this by replacing the non-atomic "check-then-create" pattern with an atomic os.makedirs(..., exist_ok=True) call. This ensures that if the directory already exists (even as a symlink), the operation doesn't fail and doesn't follow the symlink in an insecure way.
The analysis of the commit dec4cec5d16edaf83a00a658f32d1e032661cebc reveals changes in three key functions across two files:
-
virtualenv.app_data.make_app_data: This function is responsible for creating the application data directory. The patch replaces a vulnerable if not os.path.isdir(folder): os.makedirs(folder) block with os.makedirs(folder, exist_ok=True). This function is a primary entry point for the vulnerability when virtualenv initializes its application data cache.
-
virtualenv.util.lock._CountedFileLock.__init__: This constructor for a file lock also contained a similar TOCTOU vulnerability when creating the parent directory for the lock file: if not os.path.isdir(parent): os.makedirs(parent). This was also replaced with an atomic os.makedirs(parent, exist_ok=True).
-
virtualenv.util.lock._FileSystemMutex._lock_file: This function, responsible for creating a mutex lock file, was also vulnerable. It called os.makedirs(str(self.path)) without exist_ok=True, which is now added in the patch. This could be exploited to manipulate lock files.
These three functions are the direct locations of the vulnerable code and would appear in a runtime profile if the race condition were to be triggered during the execution of virtualenv.