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:
| Label | Covers | Typical meaning |
|---|---|---|
| read | All GET and HEAD requests | See a resource, not change it |
| write | POST, PUT, PATCH and DELETE | Modify the resource |
| execute | Requests to the ZMQ and websocket channels, which means terminals and kernels | Usually 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:
- Whoever can execute can write files, since a kernel can write files.
- Whoever can write files may be able to change notebooks other people later open.
- 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
- Security in the Jupyter Server, Jupyter documentation, fetched 19 October 2026.
Last reviewed: 19 October 2026.