Safely Opening Untrusted Jupyter Notebooks with Trusted Notebook Signing
Learn how to use Jupyter's trusted notebook signing to safely open external notebooks: isolate the signing key, review content, explicitly trust via CLI or UI, and verify trust loss when moving between environments.
25 Jun 2026, 02:31 UTC

Desired outcome
Open notebooks that originate from external sources (shared files, CI artifacts, public repositories) without automatically executing embedded JavaScript or HTML output. Use Jupyter's built‑in notebook signing mechanism to explicitly mark a notebook as trusted only after a manual review, keeping the execution environment safe for production workloads.
Prerequisites
- Jupyter Notebook or JupyterLab ≥ 6.0 installed for the user that will run the notebooks.
- A dedicated user profile or a clean Jupyter data directory (e.g.
JUPYTER_DATA_DIR=/opt/jupyter/prod) so that the signing key is isolated from personal development environments. - Familiarity with the command line; the
jupyter trustCLI is the fastest way to script trust decisions.
Procedure
1. Launch Jupyter with an isolated data directory
export JUPYTER_DATA_DIR=/opt/jupyter/prod
jupyter lab --no-browser --port=8888
Running with a dedicated JUPYTER_DATA_DIR creates a fresh nbsignature database (the per‑user HMAC key) that is not shared with any other profile. This prevents a compromised key from affecting other users.
2. Open the notebook from the untrusted source
Navigate to the notebook file in the Jupyter file browser or load it via File → Open from Path. The notebook will display a yellow banner: “Untrusted notebook – JavaScript and HTML output disabled.” All code cells are visible, but any IPython.display.HTML, JavaScript, or display_javascript output appears as a static preview.
3. Review the notebook content
- Inspect every code cell for malicious logic (e.g.,
os.system,subprocess.run, network calls). - Check markdown cells for embedded
<script>tags oriframeelements. - Verify that output cells do not contain unexpected HTML/JS – they will be shown as plain text while untrusted.
4. Explicitly trust the notebook (CLI)
jupyter trust /opt/jupyter/prod/notebooks/incoming_analysis.ipynb
The command writes a signatures entry into the notebook metadata, signed with the HMAC key stored in $JUPYTER_DATA_DIR/nbsignature.db. After this step the banner disappears and HTML/JS outputs render normally.
5. Explicitly trust the notebook (UI)
In the notebook toolbar click File → Trust Notebook. A confirmation dialog appears; confirming performs the same metadata update as the CLI.
6. Save the notebook (optional)
When the notebook is saved while trusted, Jupyter re‑signs it automatically, keeping the trust state portable **only** within the same user and signing key.
Expected checks
- Banner disappearance – after trust, the yellow warning banner should no longer be present.
- Metadata inspection – open the notebook file in a text editor and locate the
metadata.signaturesobject. It contains a base64‑encoded HMAC; its presence confirms the notebook is trusted in this environment. - Output rendering – cells that previously showed static previews of HTML/JS now execute and display interactive output.
Recovery options
Revoking trust
If a notebook is later deemed unsafe, remove its signature:
jupyter trust --remove /opt/jupyter/prod/notebooks/incoming_analysis.ipynb
The notebook reverts to untrusted state; the banner reappears and JavaScript/HTML output is again disabled.
Key rotation / profile migration
Changing JUPYTER_DATA_DIR or deleting nbsignature.db invalidates all existing signatures. Notebooks will appear untrusted until re‑reviewed and re‑trusted. This is intentional – it forces a fresh audit after any environment change.
Limitations
- Trust is user‑ and key‑specific. Moving a trusted notebook to another machine, another user, or a different
JUPYTER_DATA_DIRdrops the trust automatically. - Code execution is not sandboxed. Trusting only enables rendering of HTML/JavaScript output. Malicious Python code still runs when a cell is executed. Always review code cells before running them.
- No automatic revocation. There is no expiration or central revocation list; you must manually run
jupyter trust --removefor each notebook.
Practical verification steps (for human review)
- Open a known‑good notebook from an external source in the isolated profile. Confirm the untrusted banner appears.
- Run
jupyter trust <path>and verify the banner disappears. - Copy the same notebook to a different user’s home directory (or a second
JUPYTER_DATA_DIR) and open it. The banner should reappear, demonstrating key binding. - Inspect the notebook JSON for the
signaturesfield after each step to see it added and removed.
Summary checklist
| Step | Command / Action | Verification |
|---|---|---|
| Isolate environment | export JUPYTER_DATA_DIR=… | New nbsignature.db created |
| Open notebook | UI file browser | Untrusted banner shown |
| Review cells | Manual inspection | No hidden malicious code |
| Trust notebook | jupyter trust <path> or UI | Banner gone, signatures present |
| Re‑verify after move | Copy to another profile | Banner returns, trust lost |
Following this workflow gives you a repeatable, auditable process for handling notebooks that cross trust boundaries while keeping the Jupyter front‑end safe from drive‑by script execution.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.