From 1590fd3de051b385c0e95fa67aef4563f396acbd Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 6 Jun 2026 18:58:07 +0200 Subject: [PATCH 01/48] docs: document IFRAME_CSP on the Artifacts page IFRAME_CSP (a Content-Security-Policy injected into artifact and preview srcdoc iframes) is already covered in the env reference and the hardening guide. This fills the user-facing gap: an artifact-CSP section and a blank-preview troubleshooting entry on the Artifacts page, linking to both, with the correct variable name, scope, and prepend-first-wins behaviour. Based on the intent of PR #1249. Co-Authored-By: michaellrowley <13807564+michaellrowley@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) --- .../chat-features/code-execution/artifacts.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/features/chat-conversations/chat-features/code-execution/artifacts.md b/docs/features/chat-conversations/chat-features/code-execution/artifacts.md index 5d2bcd2fbe..187a8e268d 100644 --- a/docs/features/chat-conversations/chat-features/code-execution/artifacts.md +++ b/docs/features/chat-conversations/chat-features/code-execution/artifacts.md @@ -32,6 +32,22 @@ When Open WebUI creates an Artifact, you'll see the content displayed in a dedic - **Updates**: Open WebUI may update an existing Artifact based on your messages. The Artifact window will display the latest content. - **Actions**: Access additional actions for the Artifact, such as copying the content or opening the artifact in full screen, located in the lower right corner of the Artifact. +## Securing artifact previews with a CSP + +Artifact previews render inside a sandboxed `srcdoc` iframe. For tighter control over what that generated HTML can do (outbound network calls, scripts, styles), inject a dedicated Content Security Policy into the preview with the [`IFRAME_CSP`](/reference/env-configuration#iframe_csp) environment variable, separate from the main app's `CONTENT_SECURITY_POLICY`. + +It is empty by default (the iframe `sandbox` already provides baseline isolation) and applies to **every** `srcdoc` iframe in the UI: Artifacts, code/HTML previews, file previews and citation modals. When set, Open WebUI prepends a `` tag to the iframe document, and per the CSP spec the first policy wins, so it overrides any CSP the generated HTML already declares. A reasonable starting point: + +```bash +IFRAME_CSP=default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:; connect-src 'none' +``` + +That keeps inline scripts and styles working (most artifacts need them) while blocking `fetch` / `XMLHttpRequest` / `WebSocket`, so an artifact cannot quietly call out to the network. + +:::tip Start permissive, then tighten +An overly strict policy can make a preview appear blank, since many artifacts rely on inline ` ``` -:::warning Requires `allowSameOrigin` — otherwise `window.args` is silently `undefined` +:::warning Requires `allowSameOrigin`, otherwise `window.args` is silently `undefined` The args are injected from the parent page via `iframe.contentWindow.args = ...`, which the browser blocks under same-origin policy unless the iframe sandbox carries `allow-same-origin`. That is gated by the per-user **Settings → Interface → "iframe Sandbox Allow Same Origin"** toggle, which is **off by default**. If `window.args` comes back undefined and you have not changed this setting, that is the cause: turn it on and reload. See [allowSameOrigin](#allowsameorigin) above for the security trade-off. ::: :::note Where `window.args` is set, and where it is not -- ✅ **Tool method returning `HTMLResponse` or `(HTMLResponse, context)` tuple** — rendered inline at the "View Result from..." tool call indicator. `window.args` is injected (subject to the `allowSameOrigin` requirement above). -- ❌ **`__event_emitter__({"type": "embeds", "data": {"embeds": [...]}})`** — rendered through the chat-controls Embeds panel, which does not wire `args` at all. `window.args` will always be undefined here, regardless of sandbox settings. This is by design: the embeds-event path has no tool call attached, so there are no args to inject. -- ❌ **Action embeds** — triggered by the user, not the model, so there are no model-supplied args to inject. +- ✅ **Tool method returning `HTMLResponse` or `(HTMLResponse, context)` tuple**: rendered inline at the "View Result from..." tool call indicator. `window.args` is injected (subject to the `allowSameOrigin` requirement above). +- ❌ **`__event_emitter__({"type": "embeds", "data": {"embeds": [...]}})`**: rendered through the chat-controls Embeds panel, which does not wire `args` at all. `window.args` will always be undefined here, regardless of sandbox settings. This is by design: the embeds-event path has no tool call attached, so there are no args to inject. +- ❌ **Action embeds**: triggered by the user, not the model, so there are no model-supplied args to inject. If you need to pass dynamic data into an embed rendered via either of the ❌ paths, use the [Payload Requests](#payload-requests) pattern above instead. ::: ### Auto-Injected Libraries -When `allowSameOrigin` is enabled, the iframe component auto-detects usage of certain libraries in your HTML and injects them automatically — no CDN `" + ) + + async def script(): + return Response(MY_JS, media_type="application/javascript") + + async def style(): + return Response(MY_CSS, media_type="text/css") + + app.add_api_route("/my/tool", page, methods=["GET"]) + app.add_api_route("/my/tool.js", script, methods=["GET"]) + app.add_api_route("/my/tool.css", style, methods=["GET"]) ``` -Call from the first hook with access to `__request__.app`. The idempotency guard is important: the loader may re-execute on edits, and `add_api_route` will happily register the same path twice. +Call from the first hook (or a `system.startup.completed` event) that has `__request__.app` / `__app__`. The idempotency guard matters: the loader may re-execute on edits, and `add_api_route` registers the same path twice without complaint. + +`__app__` is the **real** FastAPI app, so a route can return anything HTTP can carry: JSON, `HTMLResponse`, JavaScript, CSS, images, even a whole bundled SPA. You can host an entire standalone tool at its own URL, shipped as a plugin, with **no frontend rebuild**. This is how a plugin serves a ToS/consent page, an approval screen, an OAuth callback, a status dashboard, or a one-click-installer UI. + +**The line to not blur:** a route is *your own page*. Your page can reference your own `/my/tool.js` and `/my/tool.css` and they load fine. It does **not** inject into the Open WebUI chat UI. Registering `/my/tool.js` does not make Open WebUI's own `index.html` load it; the user only gets your asset by navigating to *your* route. + +To put your JS/CSS into the **actual** Open WebUI SPA (a button on real messages, a theme over the real app, a first-run tour over the real interface), the frontend has to reference your asset. That means writing into the custom-CSS / custom-JS loader seam at startup, which is the indirect, fragile path. A dedicated asset-injection primitive is what would formalize that seam so multiple plugins can do it safely. Route registration alone gets you **pages**, not **injection**. + +:::warning +A registered route runs on the real application and is **not** authenticated unless you add an auth dependency yourself. Anything you expose at a path is reachable by anyone who can reach the server, so gate sensitive routes (admin checks, signed tokens) explicitly. +::: ### 4. Spawn a background task diff --git a/docs/features/extensibility/plugin/functions/event.mdx b/docs/features/extensibility/plugin/functions/event.mdx index 49bcce2898..a58572f907 100644 --- a/docs/features/extensibility/plugin/functions/event.mdx +++ b/docs/features/extensibility/plugin/functions/event.mdx @@ -180,6 +180,7 @@ Because the handler receives `__app__` (the FastAPI application), an Event funct - **Self-installing / self-configuring plugins.** On `system.startup.completed`, check whether a component is installed and configured, and if not, provision it by calling the admin endpoints, using values from your Valves. Admins configure everything from inside Open WebUI instead of fiddling with manual setup. - **Custom flows that span a request and an event.** For example, an **email-verification** flow: on `system.startup.completed` register a `/verify` endpoint; on `auth.signup` email the new user a tokenized link; when they click it and hit your endpoint, flip their role from `pending` to `user`. A complete activation flow with no external service, as one function. +- **Server-rendered pages, not just JSON.** A registered route can return HTML, JavaScript, CSS, or a whole bundled SPA (FastAPI `HTMLResponse` / `Response`), so a function can host its own consent page, status dashboard, approval screen, or installer UI at its own URL **without a frontend rebuild**. Example, a **versioned ToS gate**: hold new accounts as `pending`, serve the agreement at `/tos`, flip the role to `user` on acceptance, and store the accepted version in the user's settings so bumping the ToS re-gates everyone automatically. Note the boundary: this serves *your own page*, it does not inject into the Open WebUI chat UI itself, see [Serve a page or asset from a route](/features/extensibility/plugin/development/under-the-hood#3-serve-a-page-or-asset-from-a-route). :::warning Registering routes and calling admin endpoints from a function is powerful and effectively unrestricted. Treat any Event function as trusted, server-level code. @@ -207,50 +208,49 @@ An Event function runs **after** the activity it reacts to (the user is already Fire on `auth.signup` / `user.created` to shape a new user's first five minutes, and on `system.startup.completed` to provision the instance itself. -- **Welcome chat.** Create a pre-populated chat for the new user (with a getting-started message, links, and screenshots), then emit a socket event so it appears in their sidebar, optionally with a notification pointing them to it. -- **Auto-group assignment.** Add the new user to Valve-configured default groups so they inherit the right models, channels, and permissions from day one. -- **Apply interface defaults.** Push your admin-chosen UI defaults onto each new user's settings. Pair with `function.valves_updated` to re-apply across all existing users when you change the defaults, the configuration-as-data replacement for hand-editing each account. -- **Email verification.** Register a `/verify` endpoint on startup, email the new user a tokenized link on signup, and flip their role from `pending` to `user` when they click it. A full activation flow with no external service (see [Registering Endpoints](#registering-endpoints-and-self-installing-plugins)). -- **Seed starter content.** Create a starter knowledge base, a set of prompts, or a personal channel for each new user. +- **Welcome chat.** Drop a pre-populated getting-started chat into the new user's sidebar, with an optional notification pointing at it. +- **Auto-group assignment.** Add new users to default groups so they inherit the right models, channels, and permissions on day one. +- **Apply interface defaults.** Push admin-chosen UI defaults onto new users, and re-apply to everyone when you change them. +- **Email verification.** Email a tokenized link on signup; clicking it flips the account from `pending` to `user`. No external service ([how](#registering-endpoints-and-self-installing-plugins)). +- **Seed starter content.** Give each new user a starter knowledge base, prompt set, or personal channel. +- **Progressive onboarding drip.** Send a scheduled series (day 1 welcome, day 3 tips, day 7 advanced) based on each user's account age. +- **Feature-launch announcer.** Push a one-time announcement chat or notification to all existing users when you ship something new. ### Access control and signup gating Because the account already exists when the event fires, gating means *holding or removing* it, not rejecting the request. -- **Domain allowlist.** On `auth.signup`, check the email domain against a Valve allowlist, auto-approve matches, hold everyone else as `pending`. -- **Disposable-email block.** Reject signups from known throwaway domains, on its own or combined with email verification for real signup hygiene. -- **Burst defense.** Track signups per Valve-tuned window and auto-hold new accounts during a spike (bot-signup defense). -- **Approval queue.** Post "User X wants access [Approve] / [Deny]" to Slack or Discord with buttons that hit a registered endpoint, so an admin approves from their phone with no Open WebUI login. +- **Email-domain policy.** Allowlist trusted domains, hold the rest as `pending`, reject disposable or throwaway domains. +- **Burst defense.** Auto-hold new accounts during a signup spike (bot defense). +- **Approval queue.** Post "User X wants access [Approve] / [Deny]" to Slack or Discord, approve from your phone. ### Lifecycle and housekeeping Register a periodic background task on `system.startup.completed` (see [Spawn a background task](/features/extensibility/plugin/development/under-the-hood#patterns)) and let it run on a schedule. -- **Self-cleaning chats.** Archive or delete chats older than N days (Valve-configurable). The recurring "prune" job, built in. +- **Self-cleaning chats.** Archive or delete chats past an age cutoff. Use `chat.created` as a throttled heartbeat instead of a cron box. - **Orphaned-knowledge GC.** Periodically prune knowledge files no model references anymore. -- **Offboarding cascade.** On `user.deleted`, revoke the user's API keys, reassign or purge their shared resources, and disable their automations. One event, clean teardown. -- **Scheduled maintenance.** Any recurring upkeep your instance needs, scheduled from one place instead of an external cron box. +- **Offboarding cascade.** On `user.deleted`, revoke API keys, purge shared resources, disable automations. Clean teardown. ### Compliance and audit -- **Privilege-escalation alarm.** On `user.role_updated`, if an account is promoted to **admin**, raise a loud, multi-sink alert: post to an Open WebUI channel, email the admins, **and** write to your logging stack or SIEM. In a single-trust-domain instance a new admin is the single highest-signal security event there is, so make it impossible to miss, not a quiet log line. -- **Immutable audit sink.** Subscribe to every event and ship a sanitized record to an append-only store (object-locked S3) or a SIEM. Tamper-evident audit logging, for free. -- **Config-change alerts.** On `config.updated` / `config.models.updated`, diff old to new and post "Admin X changed the default model" to a compliance channel. Change management without a separate tool. -- **Content flagging.** On `message.created`, scan content against a regex or classifier and flag or alert on secrets and PII. (To *redact or block* before a message is sent, use a [Filter](./filter) `outlet`, this is detection after the fact.) +- **Event-driven alerting.** Fan out a loud multi-sink alert (channel + email + SIEM) on a high-signal event. Flagship: scream when someone becomes **admin**; same pattern for `config.*` changes. +- **Immutable audit sink.** Ship every event to an append-only store or SIEM. Tamper-evident audit logging, for free. +- **Content flagging.** Scan `message.created` for secrets and PII and flag it. (To block in-band, use a [Filter](./filter).) +- **Access recertification.** Periodically ask resource owners to re-approve who can access their stuff. Automated access reviews. ### Instance-as-code and fleet ops -- **Bootstrap from manifest.** On `system.startup.completed`, read a Valve manifest (connectors, models, prompts, knowledge) and idempotently provision the whole instance to spec. New deployment, paste manifest, fully configured. -- **Self-installing components.** On startup, check whether an integration is present and, if not, provision it by calling the admin endpoints with values from your Valves. One function becomes a one-click install-and-configure for a tool that previously needed manual setup. -- **GitOps sync.** On startup and on a schedule, pull prompts, models, groups, and config from a central git repo and apply them, so a fleet of instances stays in lockstep. -- **Backup on change.** On `config.updated`, snapshot config to external storage, or to the backend's persisted `/data` directory, for point-in-time recovery. -- **Model retirement with reassignment.** Set a *retiring* model and a *destination* model in Valves; on `function.valves_updated`, rewrite every model definition (`base_model_id`) and every automation that still references the retiring model to point at the destination. Decommission a model without leaving dangling references or silently broken automations behind. +- **Bootstrap from manifest.** Provision a whole instance to spec from a Valve manifest. New deployment, paste manifest, done. +- **GitOps sync.** Pull prompts, models, groups, and config from a central git repo so a fleet stays in lockstep. +- **Backup on change.** Snapshot config on every `config.updated`, to external storage or the persisted `/data` directory. +- **Model retirement with reassignment.** Point a retiring model at a destination, and auto-rewrite every model and automation that referenced it. ### Operations and integrations -- **Self-healing connectors.** On startup and periodically, health-check each connector, auto-disable a dead endpoint, and alert, so one down backend does not break the model picker for everyone. -- **Notify-anything bridge.** Forward selected events to external services to make Open WebUI a node in a larger automation graph (n8n / Zapier style). -- **Usage metering.** Accumulate per-user token usage from message events and push periodic reports to an external system. Token *counts* come from the events, but turning them into a currency budget or a hard spend cap needs an external price source, so a true cost circuit-breaker is event-function-**plus-external**, not event-function-only. +- **Self-healing connectors.** Health-check connectors, auto-disable a dead one and alert, so the model picker stays clean. +- **Notify-anything bridge.** Forward selected events to external services, making Open WebUI a node in an automation graph. +- **Usage metering.** Accumulate per-user token usage and export it. (A real currency budget also needs an external price source.) - **Honeypot / intrusion detection.** Register decoy admin routes, then log and auto-deactivate anyone who probes them. :::warning One-time work runs once per replica diff --git a/docs/features/extensibility/plugin/index.mdx b/docs/features/extensibility/plugin/index.mdx index a93c3435ae..0abfd96d09 100644 --- a/docs/features/extensibility/plugin/index.mdx +++ b/docs/features/extensibility/plugin/index.mdx @@ -11,7 +11,7 @@ title: "Tools & Functions (Plugins)" 1. **Only install from trusted sources.** Never import Tools or Functions from unknown or untrusted sources. Malicious code can compromise your entire system. -2. **Featured does not mean vetted.** A plugin being highlighted, featured, popular, or listed on the [Open WebUI Community site](https://openwebui.com/) is **not** an endorsement and does **not** mean its code was reviewed for security or quality. Listings are community-submitted and unaudited. See [Community Plugins](/features/extensibility/plugin/community). +2. **Featured does not mean vetted.** A plugin being highlighted, featured, popular, or listed on the [Open WebUI Community site](https://openwebui.com/) is **not** an endorsement and does **not** mean its code was reviewed for security or quality. Listings are community-submitted and unaudited. See [Community Plugins](/features/extensibility/community). 3. **Review code before importing.** Before installing any community Tool or Function, review its source code. If you don't understand what it does, don't install it. diff --git a/docs/getting-started/essentials.mdx b/docs/getting-started/essentials.mdx index 8ad6f9aa7d..fee8dcf001 100644 --- a/docs/getting-started/essentials.mdx +++ b/docs/getting-started/essentials.mdx @@ -51,7 +51,7 @@ There are two plugin families: **Tools** and **Functions**. Both Tools and Functions are browsed and installed from the [**Open WebUI Community site**](https://openwebui.com/), a one-click catalog of thousands of community-built plugins. Pick one, click "Get", paste it into the admin panel, enable it, and configure its **valves** (the plugin's settings). You can also write your own from scratch in the admin panel. -New to the catalog? The [**Community Plugins**](/features/extensibility/plugin/community) guide is the beginner's map: how to find a plugin by what you want to do, and how to import it safely. One rule to internalize now: a plugin being featured or popular is **not** a security or quality review, and plugins run real code on your server, so read the source before you import. +New to the catalog? The [**Community Plugins**](/features/extensibility/community) guide is the beginner's map: how to find a plugin by what you want to do, and how to import it safely. One rule to internalize now: a plugin being featured or popular is **not** a security or quality review, and plugins run real code on your server, so read the source before you import. :::note Before you build, browse Whenever you think "it would be nice if Open WebUI did X," it almost certainly already does via a plugin. There are thousands of plugins already written, and the one you need is usually already there. Even if nothing matches exactly, the closest hit is usually only about 20 lines off from what you want and you can fork it from the admin panel. @@ -59,7 +59,7 @@ Whenever you think "it would be nice if Open WebUI did X," it almost certainly a Reference reading: - [Plugin overview](/features/extensibility) -- [Community Plugins](/features/extensibility/plugin/community): browse and import safely +- [Community Plugins](/features/extensibility/community): browse and import safely - [Tools reference](/features/extensibility/plugin/tools) - [Functions reference (Pipes/Filters/Actions)](/features/extensibility/plugin/functions) - [MCP tool servers](/features/extensibility/mcp) From 462653bcaf7fa95fb77c666f5cabe9c523625135 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Fri, 26 Jun 2026 01:12:41 +0200 Subject: [PATCH 47/48] pyodide legacy --- .../chat-features/code-execution/index.md | 18 +++++++++++++----- .../chat-features/code-execution/python.md | 8 ++++++-- .../advanced-topics/hardening.md | 8 ++++---- docs/reference/env-configuration.mdx | 4 ++-- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/docs/features/chat-conversations/chat-features/code-execution/index.md b/docs/features/chat-conversations/chat-features/code-execution/index.md index 210d7b94b4..20c2e8bbb4 100644 --- a/docs/features/chat-conversations/chat-features/code-execution/index.md +++ b/docs/features/chat-conversations/chat-features/code-execution/index.md @@ -9,7 +9,7 @@ Open WebUI offers powerful code execution capabilities directly within your chat - **Code Interpreter Capability**: Enable models to autonomously write and execute Python code as part of their responses. In Native (Agentic) Mode, the only supported tool-calling mode, this runs via the `execute_code` tool. The older XML-based mechanism is itself the legacy approach and is unsupported, so new deployments should stay on Native Mode. -- **Python Code Execution**: Run Python scripts directly in your browser using Pyodide, or on a server using Jupyter. Supports popular libraries like pandas and matplotlib with no setup required. +- **Python Code Execution**: Run Python in your browser via Pyodide or on a server via Jupyter, with no setup, for self-contained tasks. Both are now **legacy** engines: for real Python workloads (any package, full performance, shell access) use **Open Terminal**. - **MermaidJS Rendering**: Create and visualize flowcharts, diagrams, and other visual representations with MermaidJS syntax that automatically renders in your chat. @@ -23,7 +23,15 @@ These execution capabilities bridge the gap between conversation and implementat Open WebUI supports multiple code execution backends, each suited to different use cases. The right choice depends on what you need: lightweight browser-based execution, a full Python environment, or unrestricted shell access. -### Pyodide (Default) +:::tip Recommended: Open Terminal +**[Open Terminal](#open-terminal)** is the recommended backend for real code execution: full native Python, any package, any language, and shell access, isolated in a Docker container. **Pyodide** and **Jupyter** are now **legacy** engines, kept for zero-setup, in-chat use, not the path forward for serious workloads. +::: + +### Pyodide (Legacy) + +:::caution Legacy Engine +Pyodide is a **legacy** code-execution engine. It is still the built-in, zero-setup default for the in-chat Code Interpreter and remains a safe browser sandbox, but it is no longer the recommended path: for anything beyond basic analysis use **[Open Terminal](#open-terminal)**, which gives full native Python, any package, and shell access. Pyodide may be deprecated in a future release. +::: Pyodide runs Python in the browser via WebAssembly. It is sandboxed and safe for multi-user environments, but comes with some constraints: @@ -50,7 +58,7 @@ The Code Interpreter toggle and the Open Terminal toggle cannot be active at the ### Jupyter (Legacy) :::caution Legacy Engine -Jupyter is now considered a **legacy** code execution engine. The Pyodide engine is recommended for most use cases, and Open Terminal is recommended when you need full server-side execution. Jupyter support may be deprecated in a future release. +Jupyter is a **legacy** code execution engine, as is Pyodide. **Open Terminal** is the recommended backend when you need server-side execution. Jupyter support may be deprecated in a future release. ::: Jupyter provides a full Python environment and can handle virtually any task: file creation, package installation, and complex library usage. However, it has significant drawbacks in shared deployments: @@ -96,7 +104,7 @@ Terminals is licensed under the [Open WebUI Enterprise License](/enterprise), no ### Comparison -| Consideration | Pyodide | Jupyter (Legacy) | Open Terminal | Terminals | +| Consideration | Pyodide (Legacy) | Jupyter (Legacy) | Open Terminal | Terminals | | :--- | :--- | :--- | :--- | :--- | | **Runs in** | Browser (WebAssembly) | Server (Python kernel) | Server (Docker container) | Server (orchestrated containers) | | **Library support** | Limited subset | Full Python ecosystem | Full OS (any language, any tool) | Full OS (any language, any tool) | @@ -108,7 +116,7 @@ Terminals is licensed under the [Open WebUI Enterprise License](/enterprise), no | **Multi-user safety** | ✅ Per-user by design | ⚠️ Not isolated | ℹ️ Built-in multi-user mode (small teams) | ✅ Container-per-user with lifecycle management | | **File generation** | ✅ Write to `/mnt/uploads/`, download via file browser | ✅ Full support | ✅ Full support with upload/download | ✅ Full support with upload/download | | **Setup** | None (built-in) | Admin configures globally | Native integration via Settings → Integrations | Separate service + Docker socket or K8s cluster | -| **Recommended for orgs** | ✅ Safe default | ❌ Not without isolation | ℹ️ Best for small teams | ✅ Designed for multi-tenant orgs | +| **Recommended for orgs** | ⚠️ Legacy (safe but limited) | ❌ Not without isolation | ℹ️ Best for small teams | ✅ Designed for multi-tenant orgs | | **Enterprise scalability** | ✅ Client-side, no server load | ❌ Single shared instance | ℹ️ Single container, shared resources | ✅ Horizontally scalable (Docker or Kubernetes) | | **Idle management** | N/A | N/A | N/A (always running) | ✅ Auto-stop after configurable timeout | | **License** | MIT | MIT | MIT | [Enterprise](/enterprise) | diff --git a/docs/features/chat-conversations/chat-features/code-execution/python.md b/docs/features/chat-conversations/chat-features/code-execution/python.md index 377192d003..4d33cb80f4 100644 --- a/docs/features/chat-conversations/chat-features/code-execution/python.md +++ b/docs/features/chat-conversations/chat-features/code-execution/python.md @@ -14,6 +14,10 @@ Open WebUI provides two ways to execute Python code: Both methods support visual outputs like matplotlib charts that can be displayed inline in your chat. When using the Pyodide engine, a **persistent virtual filesystem** at `/mnt/uploads/` is available. Files survive across code executions and page reloads, and files attached to messages are automatically placed there for your code to access. +:::caution Pyodide and Jupyter are legacy engines +The in-browser **Pyodide** engine and the **Jupyter** engine are **legacy**. They remain for zero-setup, in-chat Python, but for real workloads, full package support, and shell access use **[Open Terminal](/features/chat-conversations/chat-features/code-execution#open-terminal)** instead. Pyodide may be deprecated in a future release. +::: + ## Code Interpreter Capability The Code Interpreter is a model capability that enables LLMs to write and execute Python code autonomously during a conversation. When enabled, models can: @@ -35,7 +39,7 @@ The Code Interpreter is a model capability that enables LLMs to write and execut These settings can be configured at **Admin Panel → Settings → Code Execution**: - Enable/disable code interpreter -- Select engine: **Pyodide** (recommended) or **Jupyter (Legacy)** +- Select engine: **Pyodide (legacy)** or **Jupyter (legacy)** (for full Python and shell access, use [Open Terminal](/features/open-terminal) instead) - Configure Jupyter connection settings - Set blocked modules @@ -44,7 +48,7 @@ These settings can be configured at **Admin Panel → Settings → Code Executio | Variable | Default | Description | |----------|---------|-------------| | `ENABLE_CODE_INTERPRETER` | `true` | Enable/disable code interpreter globally | -| `CODE_INTERPRETER_ENGINE` | `pyodide` | Engine to use: `pyodide` (browser, recommended) or `jupyter` (server, legacy) | +| `CODE_INTERPRETER_ENGINE` | `pyodide` | Engine to use: `pyodide` (browser, legacy) or `jupyter` (server, legacy). For full Python and shell access, use [Open Terminal](/features/open-terminal) instead. | | `CODE_INTERPRETER_PROMPT_TEMPLATE` | (built-in) | Custom prompt template for code interpreter | | `CODE_INTERPRETER_BLACKLISTED_MODULES` | `""` | Comma-separated list of blocked Python modules | diff --git a/docs/getting-started/advanced-topics/hardening.md b/docs/getting-started/advanced-topics/hardening.md index 139307039e..22895994a5 100644 --- a/docs/getting-started/advanced-topics/hardening.md +++ b/docs/getting-started/advanced-topics/hardening.md @@ -613,16 +613,16 @@ Because Tools and Functions execute server-side code, any user with permission t Open WebUI has two code execution features enabled by default: ```bash -# Allows code blocks in chat responses to be executed (default: true, engine: pyodide) +# Allows code blocks in chat responses to be executed (default: true; engine pyodide, legacy) ENABLE_CODE_EXECUTION=true CODE_EXECUTION_ENGINE=pyodide -# Allows the model to run code as part of its reasoning (default: true, engine: pyodide) +# Allows the model to run code as part of its reasoning (default: true; engine pyodide, legacy) ENABLE_CODE_INTERPRETER=true CODE_INTERPRETER_ENGINE=pyodide ``` -The default engine is `pyodide`, which runs Python in the browser via WebAssembly and does not execute code on the server. If you switch to Jupyter (`jupyter`), code runs on the Jupyter server, which has server-side access. Secure the Jupyter instance accordingly if using this engine. +`pyodide` (browser/WebAssembly) and `jupyter` (server) are **legacy** code-execution engines. **If you do not need in-chat code execution, disable both features** by setting `ENABLE_CODE_EXECUTION=false` and `ENABLE_CODE_INTERPRETER=false`. If you do need it, isolate it: prefer **[Open Terminal](/features/open-terminal)**, which runs code in a separate Docker container, with **[Terminals](/enterprise)** for per-user isolation in multi-tenant deployments. Do not treat the browser-based `pyodide` engine as a security boundary, and never expose the `jupyter` engine without securing the Jupyter instance, which has direct server-side access. ### Safe Mode @@ -796,7 +796,7 @@ For organizations where security is a priority, the following practices define t 7. **Keep Tool and Function creation restricted to administrators and review all code before importing.** By default, only administrators can create, import, and manage Tools and Functions. Do not grant workspace permissions to untrusted users. Treat third-party Tools with the same scrutiny as any code running on your infrastructure. Never import Tools without reviewing their source code first. [Details](#tools-functions-and-pipelines) -8. **Disable automatic dependency installation and disable code execution if not needed.** Set `ENABLE_PIP_INSTALL_FRONTMATTER_REQUIREMENTS=false` to prevent Tools from pulling in arbitrary packages at runtime. If your deployment does not require in-chat code execution, disable it entirely. If it is needed, keep the default `pyodide` engine, which runs in the browser, not on the server. Do not switch to the Jupyter engine without securing the Jupyter instance. Keep direct connections and direct tool servers disabled. [Details](#dependency-installation) +8. **Disable automatic dependency installation and disable code execution if not needed.** Set `ENABLE_PIP_INSTALL_FRONTMATTER_REQUIREMENTS=false` to prevent Tools from pulling in arbitrary packages at runtime. If your deployment does not require in-chat code execution, disable it entirely (`ENABLE_CODE_EXECUTION=false`, `ENABLE_CODE_INTERPRETER=false`). If it is needed, isolate it with **Open Terminal** (container-isolated) rather than relying on the legacy `pyodide` or `jupyter` engines, and never expose a `jupyter` engine without securing the Jupyter instance. Keep direct connections and direct tool servers disabled. [Details](#dependency-installation) ### Data Protection diff --git a/docs/reference/env-configuration.mdx b/docs/reference/env-configuration.mdx index 6c9c287503..a222922d7c 100644 --- a/docs/reference/env-configuration.mdx +++ b/docs/reference/env-configuration.mdx @@ -1232,7 +1232,7 @@ The format for the JSON response is strictly: - Type: `str` - Default: `pyodide` -- Description: Specifies the code execution engine to use. +- Description: Specifies the code execution engine to use. `pyodide` (browser) and `jupyter` (server) are **legacy** engines; for full Python and shell access use [Open Terminal](/features/open-terminal) instead. - Persistence: This environment variable is a `ConfigVar` variable. #### `CODE_EXECUTION_JUPYTER_URL` @@ -1283,7 +1283,7 @@ The format for the JSON response is strictly: - Type: `str` - Default: `pyodide` -- Description: Specifies the code interpreter engine to use. +- Description: Specifies the code interpreter engine to use. `pyodide` and `jupyter` are **legacy** engines; for full Python and shell access use [Open Terminal](/features/open-terminal) instead. - Persistence: This environment variable is a `ConfigVar` variable. #### `CODE_INTERPRETER_BLACKLISTED_MODULES` From b7929aeb76025a56498953c2d84f014cd6fe3a8e Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Fri, 26 Jun 2026 01:40:32 +0200 Subject: [PATCH 48/48] Update index.mdx --- docs/features/extensibility/plugin/index.mdx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/features/extensibility/plugin/index.mdx b/docs/features/extensibility/plugin/index.mdx index 0abfd96d09..713475d1f8 100644 --- a/docs/features/extensibility/plugin/index.mdx +++ b/docs/features/extensibility/plugin/index.mdx @@ -3,8 +3,20 @@ sidebar_position: 100 title: "Tools & Functions (Plugins)" --- +import ThemedImage from '@theme/ThemedImage'; +import useBaseUrl from '@docusaurus/useBaseUrl'; + # 🛠️ Tools & Functions + + :::danger ⚠️ Critical Security Warning **Tools, Functions, Pipes, Filters, and Pipelines execute arbitrary Python code on your server.** This is by design: it's what makes them powerful. However, this also means: