Today I learned: Python's .start Files as a Persistence Mechanism
Explains PEP 829's new .start files in Python 3.15, which let a package register package.module:callable entries in site-packages that execute automatically every time an interpreter starts, before any user code runs. The author walks through a reproducible lab showing code execution via a .start file, contrasts it with the older executable-import .pth file technique it replaces, and gives forensic hunting commands (using python -S to avoid triggering the mechanism during investigation) to locate and audit .start files on disk.
What it is
PEP 829 introduces .start files in Python 3.15, a structured replacement for the executable import lines previously allowed inside .pth files. A .start file in a site-packages directory contains a package.module:callable reference; Python resolves and invokes that callable during interpreter startup, before any user code runs.
How it works
Python already scans site-packages directories for .pth files during site module initialization. .start files live in the same directories and are processed alongside them, in alphabetical filename order per directory. Each line in a .start file is a reference like foo.submod:initialize; Python imports foo.submod, retrieves initialize, and calls it with no arguments. Unlike .pth executable imports, the file cannot contain arbitrary statements — only these structured references — which improves auditability but does not remove pre-start code execution. A migration detail: if a .start file and a .pth file share the same base name, executable import lines in that .pth file are ignored, so finding both artifacts doesn't mean both mechanisms were active.
Preconditions / Affected
Requires Python 3.15 (final release scheduled October 9, 2026; the post was tested against 3.15.0rc3). An attacker needs write access to an applicable site-packages directory — scope depends on whether that's a single virtualenv, a user's installation, or a system-wide interpreter.
What to do
To enumerate .start files without triggering them, suppress site processing with -S:
python3.15 -S -c 'import site; print(site.getsitepackages())'For a full hunt, the post gives a script run under -S that walks site.getsitepackages() plus site.getusersitepackages(), globs for *.start, and prints each file's reference lines. For a broader forensic sweep (application-bundled or custom venvs may not appear in the system interpreter's site directories), search the filesystem directly:
find /usr /usr/local /opt /home -type f -name '*.start' -print 2>/dev/nullWhen a .start file is found, the author recommends correlating its creation/modification times with the referenced module, confirming both belong to an expected package, and checking application-specific virtualenvs separately — a legitimate .start file isn't inherently suspicious; unexpected provenance or modification is the signal.
Caveats
The author states they have not found evidence of this mechanism being abused in the wild, noting Python 3.15 is still new at time of writing.
Organisations named here
- PEP 829
Technologies named here
- Python
- site
- python3.15 -S flag
- find
- venv
Techniques named here
- .start file abuse as persistence/pre-execution mechanism
- .pth file executable import line abuse
Related in Blue Team & Detection
AI-Coded Malware | Analyzing Vibe-Coded AD Enumeration | Huntress
