Your own code

Attacks on the supply chain do not only stem from dependencies; your own code can also provide points of entry. A PyPI token hard-coded into the source code, once uploaded to a public repository, provides everything needed to launch an attack, compromise your account and publish malicious packages under your name. Apart from secrets, common security flaws are often hidden in everyday coding patterns that may initially appear harmless during a code review and can be overlooked by humans. Detecting these using a linter is the first line of defence.

Detect security vulnerabilities with Ruff

Ruff is a fast Python linter that includes comprehensive security rules from Bandit:

$ uvx ruff check --select S .

See also

Further information can be found in the Ruff security rules documentation.

For future checks, you can configure ruff in the pyproject.toml file:

[tool.ruff]
lint.select = ["S"]

The ["S"] security rules, which use Bandit checks, detect hard-coded secrets, weak encryption and insecure deserialisation. Ruff runs in less than a second, so you can run it whilst typing in your IDE and before every commit. All three vulnerabilities mentioned above are detected, along with many more, including:

Rule

Description

S105

Hard-coded secrets

S301

Pickle and other insecure deserialisation

S307

Use of eval() with untrusted input

S113

Missing timeouts

S324

Weak cryptography, such as MD5 collisions

S608

SQL injection via string formatting

You can also integrate Bandit into Jupyter Notebooks, IDEs and prek.

You can also use Pysa for taint analysis.

For GitHub repositories, you can alternatively use CodeQL; see also codeql-action.

Trusted publishing

In an earlier section, we’ve already provided some guidance on how to secure the publication of Python packages on PyPI: