Safeguard
Security Guides•

What does the execute permission mean in Jupyter Server?

Jupyter Server labels requests read, write or execute. Why the execute label usually equals arbitrary code execution, and what that means for access rules.

Safeguard Security Team
3 min read

In Jupyter Server, execute covers requests to kernels and terminals, and the documentation says it usually means arbitrary code execution. Because that is generally equivalent to every other permission, a custom rule that allows execute is effectively full access for that user.

Definition

Since version 2.0, Jupyter Server separates two steps. Authentication identifies who is making a request. Authorization decides whether that user may take the action. Authorization runs only for requests that are already authenticated, and a refusal returns a 403 error.

Each request gets one of three labels:

LabelCoversTypical meaning
readAll GET and HEAD requestsSee a resource, not change it
writePOST, PUT, PATCH and DELETEModify the resource
executeRequests to the ZMQ and websocket channels, which means terminals and kernelsUsually arbitrary code execution

The documentation adds that these permissions should generally be considered sufficient to perform the equivalent of nearly all other permissions through other means. In its table for the kernels resource, connecting to kernel websockets is described as generally meaning arbitrary code execution, and as equivalent to having all other permissions.

Why this matters for design

A common idea is to give analysts a read only view of a server and keep write for a few people. That works for files. It does not work if the same people can reach a kernel, because a kernel can read and change anything the server account can.

Think in these terms:

  1. Whoever can execute can write files, since a kernel can write files.
  2. Whoever can write files may be able to change notebooks other people later open.
  3. Whoever can execute runs as the server's operating system account, not as a limited web user.

What to do with this

  • Run the server under an account that has only the access analysts need.
  • Do not rely on a custom authorizer for isolation between users who can all execute.
  • Where users need separation, give each their own server and container, as multi user setups do. See the companion post about JupyterHub.
  • Keep secrets and production credentials out of any account a kernel runs as.
  • Log who started kernels and when, if your platform supports it.

Writing a custom authorizer

The base class requires a method that receives the handler, the user, the action and the resource, and returns true or false. That is a useful hook for blocking, for example, changes to configuration for non admins. Use it for finer rules on read and write, with the limit above in mind.

Related reading

For a network exposure checklist see /resources/blog/jupyter-server-exposed-to-the-network-checklist, and for extension risk see /resources/blog/can-a-jupyterlab-extension-run-code-on-the-server.

Safeguard's agent identity and policy features address AI agents and pipelines, not Jupyter itself. For notebook projects, the free scan at gold.safeguard.sh/scan covers dependencies.

Quick check

Can a read only user be safe if they can open a kernel?

No. A kernel runs code, so connecting to one is generally equivalent to all other permissions.

What does a failed authorization return?

A 403 Forbidden response.

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.