Safeguard
Developer Tools•

Does %pip install in a notebook leave a dependency record?

%pip install changes the notebook kernel's environment but leaves no manifest. How to turn notebook installs into a pinned file that you can scan.

Safeguard Security Team
3 min read

Not by itself. The IPython %pip magic runs the pip package manager within the current kernel, so it changes that environment, but it does not write a requirements file or lockfile. A scanner that reads manifests will not see packages that exist only in an install cell. Record them in a pinned file.

What the magic does

The IPython documentation describes %pip as running the pip package manager within the current kernel, with usage %pip install [pkgs], and %conda the same way for conda. It also says magics are specific to and provided by the IPython kernel, so availability depends on the kernel.

The practical result is that the notebook can install what it needs on first run. That is handy for exploration. It also means the notebook's dependency list is a line of code in a cell, and any installed version is whatever was newest at the time.

Why this is a security gap

Three issues come up in reviews.

First, nothing pins the version. Two runs a month apart can use different releases, and one may have an advisory the other does not.

Second, tools that inventory dependencies from manifests, such as requirements files, lockfiles and project files, have nothing to read for those packages. Whether a particular scanner reads notebook cells is a question for its documentation, so ask your vendor rather than assume.

Third, the installed environment disappears when the kernel or container does, so the evidence of what ran goes with it.

Turn install cells into a record

  1. Collect every install line from the notebook.
  2. Put the package names in a requirements input file for the project, with exact versions for anything that touches production data.
  3. Replace the install cell with a note that points to the file, and install from it when you build the environment.
  4. Commit the file next to the notebook.
  5. Add a short check cell that prints key package versions, so the executed notebook records what ran.
import importlib.metadata as md

for name in ["pandas", "numpy", "requests"]:
    print(name, md.version(name))

Review table

PracticeWhy
No unpinned install in shared notebooksPrevents silent version drift
Install in the environment build, not at run timeGives you a reviewable, repeatable step
One manifest per projectGives scanners and reviewers a file to read
Print versions in the runLeaves evidence in the executed output

Try it yourself

Click through it at your own pace, or open it full screen. Look at how an inventory is built from declared dependencies.

Where Safeguard fits

Safeguard's dependency scanning and SBOM generation work from the manifests in a repository, so a committed requirements file gives them something to inventory. You can try a free scan.

Quick check

Should I use %pip or !pip in a notebook?

The IPython docs describe %pip as running pip within the current kernel. The page does not compare it with a shell call, so check your kernel documentation if the difference matters.

Is one requirements file per notebook too much?

One per project is usually enough, as long as the notebooks in it share an environment.

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.