Safeguard
Developer Tools•

What is PEP 723 and should analysts use it for one-off scripts?

PEP 723 lets a single Python file declare its own dependencies in a comment block. Here is the format, what it fixes for analysts, and what it does not.

Safeguard Security Team
4 min read

PEP 723 is the standard that lets a single Python script declare its dependencies and required Python version in a comment block at the top of the file. A compatible runner reads the block and builds an environment before running. It removes the hidden "which packages did this script need?" problem, but it does not pin versions for you.

Why one-off scripts are a blind spot

Analytics teams write a lot of single files: a cleanup script, a quick export, a one-time backfill. They rarely get a requirements.txt. A year later nobody knows what the script imported, which versions it ran against, or whether any of them had advisories.

That matters for security because an unlisted dependency is an uninventoried dependency. If a vulnerability is published, you cannot answer "are we affected?" for code whose imports live only in someone's memory.

What the format looks like

The specification on packaging.python.org defines a block that starts with a line reading # /// script and ends with a line reading # ///. Every line in between is a comment holding TOML. For a script block, the fields are dependencies, a list of dependency specifiers, and requires-python, a version specifier.

# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "pandas==2.2.3",
#   "requests",
# ]
# ///

import pandas as pd

The version numbers above are only an example of the syntax. Choose the ones your script was tested with.

What the standard says, and what it leaves open

A few points from the specification are worth knowing:

  • Tools that run the script must error if the listed dependencies cannot be provided.
  • Tools may scan the file as text instead of parsing Python, so metadata-looking text inside a multi-line string may be handled differently by different tools.
  • Only one block of a given type is allowed, and an unclosed block is ignored.

The standard does not say anything about hashes or lockfiles. A dependency list with loose ranges will resolve to whatever is newest at run time. For a script that touches production data, write exact versions, or keep a lock alongside it in your runner of choice.

A simple rule for analytics teams

  1. Every script that leaves a laptop gets a metadata block.
  2. Pin exact versions for anything that reads credentials or writes to shared storage.
  3. Record the block in review like any other code change, so a new dependency is visible in the diff.
  4. Retire scripts that nobody owns, rather than keeping them runnable.

This costs a minute per script and turns a pile of mystery files into something a scanner or a person can read.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how a dependency list becomes an inventory you can check against advisories.

Where Safeguard fits

Safeguard's dependency scanning and SBOM generation work from declared dependencies, so a script with an explicit list is easier to inventory than one without. You can try a free scan on a repository that holds your scripts.

Quick check

Does PEP 723 pin my dependencies?

No. It records what you list. If you write a loose range, the runner resolves it at run time. Use exact versions for anything sensitive.

Is the block executed as code?

No. It is a comment holding TOML that a tool reads. The script itself still runs normally once the environment exists.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.