Fifteen years ago, if someone said "insecure software," your mind went to PHP. Not because the language was bad in itself, but because it was the one everybody used: the web was built on PHP, and the most-used language is always the most-attacked. Today that crown changed heads. The world's default language —and, above all, the language of artificial intelligence— is Python. And with the crown comes the bullseye.
It's worth looking at what actually happened with PHP, because the lesson isn't the one it seems.
The PHP lesson wasn't "the language is bad"
PHP earned its reputation for three things, and none of them was the syntax:
- Dangerous conveniences by default.
register_globals,includeof remote URLs, hand-rolledeval. Things that made the programmer's life easy and threw the door wide open for the attacker. - Ubiquity. It was on every shared hosting plan on the planet. A single class of flaw multiplied across millions of sites.
- A generation of developers with no security training, copy-pasting the same vulnerable pattern.
Modern PHP (7 and 8) is a reasonable, far more secure language. But the reputational damage was done, and the lesson stuck: when a language becomes the foundation of everything, its "convenient" decisions turn into planet-scale vulnerabilities.
Today the crown belongs to Python
Python is the most popular language in the world by almost any measure. And, what matters here: it is the foundation of artificial intelligence. PyTorch, TensorFlow, Hugging Face, every LLM library, all of data science, most of the AI agents being deployed right now: Python. If AI is the wave, Python is the water.
That makes it the big target of this decade, exactly as PHP was of its own. But the danger moved. It's no longer so much in the language: it's in what the language drags behind it.
Real danger number one: the supply chain
A modern Python application is almost never "your code." It's your code plus hundreds of dependencies pulled from PyPI, many of which you don't even know are there (dependencies of dependencies). Each one is code that runs with your permissions. The 2024–2026 attacks on package registries haven't been isolated accidents: they've been systematic.
The avenues are well known and still working:
- Typosquatting. A package called
python-requestsinstead ofrequests. You get one letter wrong and you've just installed malware. - Dependency confusion. If your company has an internal package named
utils, someone uploads a publicutilswith a higher version number, and your installer fetches the attacker's. - Code that runs at install time. A
pip installof a package in sdist format runs itssetup.pyon your machine, as your user, before you write a single line. It's the same class of hole that made npm'spostinstallfamous. - Compromised maintainer accounts. The package is legitimate; the owner lost their password. The next version comes with a gift.
This isn't theory. In December 2022, the nightly branch of PyTorch —one of the central pieces of the AI world— suffered a dependency-confusion attack: a malicious package named torchtriton uploaded to PyPI took precedence over the legitimate one and exfiltrated system information from anyone who installed it. The most visible project in the AI ecosystem, compromised by the most mundane avenue: the package installer.
The AI-specific vector: loading a model is running code
Here's the part almost nobody outside security knows, and it's the one that truly connects "AI" with "danger."
For years, the standard way to save and share a trained model in Python has been pickle, the language's native serialization format. The problem: deserializing a pickle can execute arbitrary code. It isn't a bug; it's how pickle works by design.
And AI models are distributed this way. People download model weights from public repositories, from strangers, and load them with torch.load(...). Loading that file —in the old configurations, which still abound— is running whatever code the file's author chose to put inside it. Downloading a model "just to try it" was, literally, executing a program written by someone you don't know.
The community reacted. Hugging Face's safetensors format was born precisely for this: it stores only numbers, never code. And recent versions of PyTorch changed their default so they won't deserialize code unless you ask explicitly. But there are millions of pickle files in circulation, and an enormous amount of tutorials, notebooks and projects still doing it the old way.
That's the precise statement, not "Python is insecure": in the AI world, the normal pattern of "download this model and try it" is a pattern of executing untrusted code.
What to do (what actually moves the needle)
This isn't about abandoning Python —that's not going to happen—. It's about treating its dependencies and its models as what they are: untrusted code that runs with your permissions.
- Pin and verify your dependencies.
pip install --require-hasheswith a lockfile. If the hash doesn't match, it doesn't install. No open version ranges in production. - Cut off install-time execution. Prefer wheels over sdists; audit any package that insists on running code at install time.
- Never load a
pickleof unknown origin. Demandsafetensors. If you must usetorch.load, do it with the option that prevents deserializing code. - Isolate. What comes off the internet and what processes it should not run with access to your secrets or your network. A container or a network-less namespace costs little and covers a lot.
- Keep an inventory (SBOM). If you don't know which packages and which models you have, you can't know whether one of them already compromised you.
The root of the matter
Python's danger isn't a flaw in Python. It's the consequence of being the foundation of everything at a moment when attacking the supply chain is the fashionable tactic. It's the same story as PHP, one ecosystem later and with far more at stake: now what's built on that foundation isn't blogs, it's the AI systems starting to make decisions.
At Xiliux we build our security tools in Rust, as a single binary, with no dependency tree for anyone to poison and no formats that execute code when opened. Not out of fashion: because the attack surface that doesn't exist doesn't have to be defended. If you worry about what you're really running when you install, or when you load a model, let's talk.
Xiliux