From 4b110d4bbf7362cc4287b793ae616e60b61e1647 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Fri, 18 Sep 2026 13:36:33 -0400 Subject: [PATCH] docs: correct the security pages' defaults and the scope of the agent, encryption and audit controls against the code --- .../agentic-application-risks.mdx | 6 +++--- docs/security/accepted-risks/auth-timing.mdx | 2 +- .../llm-output-unpredictability.mdx | 4 ++-- .../oauth-token-exchange-client-trust.mdx | 2 +- .../chat-data-privacy-and-encryption.mdx | 20 ++++++++++++------- docs/security/security-policy.mdx | 6 +++--- docs/security/supply-chain-security/index.mdx | 4 ++-- 7 files changed, 25 insertions(+), 19 deletions(-) diff --git a/docs/security/accepted-risks/agentic-application-risks.mdx b/docs/security/accepted-risks/agentic-application-risks.mdx index bb4240725d..3aa24c4f3b 100644 --- a/docs/security/accepted-risks/agentic-application-risks.mdx +++ b/docs/security/accepted-risks/agentic-application-risks.mdx @@ -21,10 +21,10 @@ Agentic systems plan, decide, call tools and carry context across steps, and the Open WebUI's role is to provide the platform and to control what an agent is *allowed* to do. Our meaningful controls are user-gated permissions, privilege limits, access control and isolation: -- **Capability is gated, not granted by default.** An agent can only act through Tools and Functions. Tool use is governed by the `workspace.tools` permission, which is **disabled by default** for non-administrators, and Function authoring is restricted to administrators. Granting either is documented as equivalent to giving that user shell access to the server (see the [Security Policy](../security-policy.mdx), Rule 10). -- **An agent cannot exceed the calling user's own privileges.** Acting on a user's behalf, it is bound by that user's role and RBAC permissions and by per-user data scoping; it cannot read or reach what the user could not. +- **Capability is gated, not granted by default.** An agent acts through Tools and Functions, the code interpreter, web search, image generation and admin-configured tool servers. Authoring or importing Tool code is governed by the `workspace.tools` permission, which is **disabled by default** for non-administrators, and Function authoring is restricted to administrators; using a published tool in chat is governed by that tool's access control. Granting either is documented as equivalent to giving that user shell access to the server (see the [Security Policy](../security-policy.mdx), Rule 10). +- **An agent cannot exceed the calling user's own privileges.** Acting on a user's behalf, it is bound by that user's role and RBAC permissions and by per-user data scoping; it cannot read or reach what the user could not through Open WebUI's own APIs. The Python inside a Tool or Function itself runs with the backend process's access, which is why authoring one is treated as shell access. - **Isolation of execution.** Server-side code execution is opt-in and administrator-configured, and for production the [Terminals orchestrator](/features/open-terminal/terminals) runs execution in per-session, container-isolated environments with configurable [security-context and resource policies](/features/open-terminal/terminals/orchestration/policies). -- **Operator guardrails.** [Filters](/features/extensibility/plugin/functions/filter), human-in-the-loop confirmation and content checks let a deployment add its own policy layer around what agents may do. +- **Operator guardrails.** [Filters](/features/extensibility/plugin/functions/filter), human-in-the-loop confirmation (tool-call approval, which defaults to automatic execution) and content checks let a deployment add its own policy layer around what agents may do. These controls bound the *consequences* of a steered or misbehaving agent. They do not, and cannot, make an autonomous agent's decisions reliably safe in every case. diff --git a/docs/security/accepted-risks/auth-timing.mdx b/docs/security/accepted-risks/auth-timing.mdx index be2e43657e..c1de63a921 100644 --- a/docs/security/accepted-risks/auth-timing.mdx +++ b/docs/security/accepted-risks/auth-timing.mdx @@ -20,7 +20,7 @@ The sign-in endpoint took measurably longer for an existing account than for a n This was reported to us and is tracked as [GHSA-7rw5-9f7q-xj36](https://github.com/open-webui/open-webui/security/advisories/GHSA-7rw5-9f7q-xj36). We addressed it in the sign-in path: authentication now performs a bcrypt comparison against a fixed dummy hash on the paths where no user, or no active credential, is found. Every sign-in attempt therefore pays the same bcrypt cost regardless of whether the account exists. -Measured, this collapses the difference from roughly 20-40x down to about 1.03x (bcrypt against bcrypt), which is indistinguishable from ordinary run-to-run variance. The practically exploitable enumeration oracle is removed. +Measured, this collapses the difference from roughly 20-40x down to about 1.03x (bcrypt against bcrypt), which is indistinguishable from ordinary run-to-run variance. The practically exploitable enumeration oracle is removed. The equalisation holds for the default bcrypt hashes; with `PASSWORD_HASH_ALGORITHM=argon2`, existing accounts pay an argon2 verify while non-existent ones pay the bcrypt dummy, so the costs diverge again. Sign-in is also rate-limited to 15 attempts per email per 3 minutes (per process without Redis), which bounds the password spraying that enumeration would seed. The millisecond residual that remains is accepted as-is. This is not a matter of further effort: what is left is bounded by physical and runtime limits (the database, the Python interpreter, CPU behaviour, operating-system scheduling and network jitter) rather than by anything Open WebUI's code can improve, so there is little more to be gained from here. The reasoning is set out in [What remains, and why it is not fixable](#what-remains-and-why-it-is-not-fixable) below. diff --git a/docs/security/accepted-risks/llm-output-unpredictability.mdx b/docs/security/accepted-risks/llm-output-unpredictability.mdx index 417d31460d..5b8b1261c1 100644 --- a/docs/security/accepted-risks/llm-output-unpredictability.mdx +++ b/docs/security/accepted-risks/llm-output-unpredictability.mdx @@ -23,8 +23,8 @@ This unpredictability is a property of how language models work. It is **not a d Open WebUI controls the system *around* the model, and we harden that surface: -- **Access control and isolation** scope what a model and its tools can reach: per-user data scoping, the [tool and function permission model](/features/extensibility/plugin/), and container-isolated code execution. -- **A model cannot exceed the calling user's own privileges.** Acting on a user's behalf, it is bound by that user's permissions; it cannot read or do what the user could not. +- **Access control and isolation** scope what a model and its tools can reach: per-user data scoping, the [tool and function permission model](/features/extensibility/plugin/), and code execution that runs in the browser (Pyodide) by default, with any server-side engine opt-in and isolated by the operator. +- **A model cannot exceed the calling user's own privileges.** Acting on a user's behalf, it is bound by that user's permissions; it cannot read or do what the user could not through Open WebUI's own APIs. - **Operator guardrails** ([filters](/features/extensibility/plugin/functions/filter), content checks, confirmation prompts) let deployments add their own policy layer. These reduce the *consequences* of bad model output. They do not, and cannot, make the model's output itself predictable or safe in every case. diff --git a/docs/security/accepted-risks/oauth-token-exchange-client-trust.mdx b/docs/security/accepted-risks/oauth-token-exchange-client-trust.mdx index f6b9272ecb..f1862e5b0b 100644 --- a/docs/security/accepted-risks/oauth-token-exchange-client-trust.mdx +++ b/docs/security/accepted-risks/oauth-token-exchange-client-trust.mdx @@ -16,7 +16,7 @@ title: "OAuth Token Exchange Client Trust" The OAuth token exchange endpoint accepts a provider access token and issues an Open WebUI session for the user that token identifies. A provider's userinfo endpoint confirms that a token is valid but never reveals which OAuth client it was issued to, so without an additional check the endpoint accepts a token minted for any client registered with the same provider, including applications the operator does not control. -The endpoint is off unless an operator sets [`ENABLE_OAUTH_TOKEN_EXCHANGE`](/reference/env-configuration#enable_oauth_token_exchange) to `True`, which is not the default, so no default deployment is affected. Everything below concerns deployments that have deliberately turned it on. +The endpoint is off unless an operator sets [`ENABLE_OAUTH_TOKEN_EXCHANGE`](/reference/env-configuration#enable_oauth_token_exchange) to `True`, which is not the default, so no default deployment is affected. Everything below concerns deployments that have deliberately turned it on. The endpoint never creates accounts: the user must already exist, matched by provider subject or, when `OAUTH_MERGE_ACCOUNTS_BY_EMAIL` is on, by email. A per-address rate limit for it (`OAUTH_TOKEN_EXCHANGE_RATE_LIMIT` and `OAUTH_TOKEN_EXCHANGE_RATE_LIMIT_WINDOW`) exists and is off until set. ## What we mitigated diff --git a/docs/security/chat-data-privacy-and-encryption.mdx b/docs/security/chat-data-privacy-and-encryption.mdx index af834099dc..fab7200c92 100644 --- a/docs/security/chat-data-privacy-and-encryption.mdx +++ b/docs/security/chat-data-privacy-and-encryption.mdx @@ -20,12 +20,12 @@ Open WebUI's standard experience is designed for self-hosted control, auditabili | Scope admin workspace list/selector visibility | Set `BYPASS_ADMIN_ACCESS_CONTROL=false` | | Production database storage exposure | Use PostgreSQL with encrypted volumes, provider encryption, TDE where available, TLS, and encrypted backups | | SQLite-only deployments | Use SQLCipher with `DATABASE_TYPE=sqlite+sqlcipher` | -| Employees asking sensitive or personal questions | Use Temporary Chat, or force Temporary Chat for all users with `USER_PERMISSIONS_CHAT_TEMPORARY_ENFORCED=true` | +| Employees asking sensitive or personal questions | Use Temporary Chat, or make it the default for non-admin users with `USER_PERMISSIONS_CHAT_TEMPORARY_ENFORCED=true` (applied by the web UI; the API is not blocked) | | Keep prompts inside your infrastructure | Use local or private model endpoints and restrict approved models by group | -| Sensitive documents being uploaded or indexed | Keep file upload and knowledge permissions off by default; grant only by group | +| Sensitive documents being uploaded or indexed | Turn the file upload permission off (it is on by default) and keep the knowledge permission off; grant only by group | | Control server-side code execution | Keep Tools and Functions restricted to trusted admins | | Chat content appearing in logs | Keep audit logging at metadata level unless body logging is explicitly approved | -| Sharing control | Keep community sharing off by default and review chat-sharing permissions | +| Sharing control | Turn community sharing off (it is on by default) and review chat-sharing permissions | | Different teams needing different trust boundaries | Run separate Open WebUI instances with separate databases, backups, credentials, operators, and model providers | ## Recommended Baseline @@ -78,12 +78,14 @@ To make Temporary Chat available by default: USER_PERMISSIONS_CHAT_TEMPORARY=true ``` -To force Temporary Chat for all users by default: +To make Temporary Chat the default for non-admin users: ```bash USER_PERMISSIONS_CHAT_TEMPORARY_ENFORCED=true ``` +The web UI applies this setting; admins are exempt, and the API does not refuse to save chats, so treat it as a UI default rather than a server-side guarantee. + Relevant permissions: - **Chat > Temporary Chat** @@ -118,6 +120,8 @@ LOG_FORMAT=json Use `REQUEST` or `REQUEST_RESPONSE` audit logging only when your log platform is approved for chat content. +Audit logging is off by default (`AUDIT_LOG_LEVEL=NONE`). Chat and chat-completion paths are excluded at every level unless `AUDIT_EXCLUDED_PATHS` is changed, bodies are truncated to 2048 bytes, and the file sink writes to `DATA_DIR/audit.log` inside the data volume. + ## Who Can Read Chat Data? ### Regular Users @@ -126,7 +130,7 @@ Regular users can read their own chats and chats explicitly shared with them. Ac ### Admin Users -Admins have broad control by design. `ENABLE_ADMIN_CHAT_ACCESS=false` and `ENABLE_ADMIN_EXPORT=false` prevent casual access through Open WebUI product surfaces. Infrastructure-level access should be handled through operator trust, access review, and separation of duties. +Admins have broad control by design. `ENABLE_ADMIN_CHAT_ACCESS=false` and `ENABLE_ADMIN_EXPORT=false` prevent casual access through Open WebUI product surfaces; with the flag off, admins can still open chats flagged internal and chats explicitly shared with them. Infrastructure-level access should be handled through operator trust, access review, and separation of duties. ### Database, Host, and Backup Operators @@ -140,6 +144,8 @@ If an external model provider is configured, prompts and context sent for infere ## What Encryption Protects +Open WebUI stores chat titles and content as plain JSON in the database, uploaded files unencrypted under `DATA_DIR/uploads` (or the configured object store), and document chunks in plain text in the vector store, so at-rest protection comes from the database, volume or storage layer (pgvector can encrypt chunk text with `PGVECTOR_PGCRYPTO=true`). + Encryption at rest helps protect against: - Lost or stolen disks. @@ -150,7 +156,7 @@ Encryption at rest helps protect against: Keep these paths inside your operational trust boundary: -- The running Open WebUI application and its database key. +- The running Open WebUI application, its database key, and `WEBUI_SECRET_KEY`, which signs sessions and by default encrypts stored OAuth tokens and client secrets (it does not encrypt chat data). - Database administrators with live query access. - Host operators with access to environment variables or mounted secrets. - Exports, logs, traces, and backups that contain chat data. @@ -172,7 +178,7 @@ For sensitive departments such as HR, legal, or regulated workloads: - Use a separate database and backups. - Use separate operators and credentials. - Use private/local models. -- Consider Enforced Temporary Chat, or enable it by default with `USER_PERMISSIONS_CHAT_TEMPORARY_ENFORCED=true`. +- Consider Enforced Temporary Chat for non-admin users with `USER_PERMISSIONS_CHAT_TEMPORARY_ENFORCED=true`. For personal or highly sensitive employee questions: diff --git a/docs/security/security-policy.mdx b/docs/security/security-policy.mdx index b96033ba3b..e431c4cf9d 100644 --- a/docs/security/security-policy.mdx +++ b/docs/security/security-policy.mdx @@ -117,7 +117,7 @@ We appreciate the community's interest in identifying potential vulnerabilities. 9. **Admin Actions Are Out of Scope**: Vulnerabilities that require an administrator to actively perform unsafe actions are not considered valid vulnerabilities. Admins have full system control and are expected to understand the security implications of their actions and configurations. This includes but is not limited to adding malicious external servers (models, tools, webhooks, functions), pasting untrusted code into Functions/Tools, or intentionally weakening security settings. Reports requiring admin negligence or social engineering of admins may be rejected. However, if you believe you have found a vulnerability that affects admins and is not caused by admin negligence or intentionally malicious actions, then we absolutely want to hear about it. This policy is intended to filter social engineering attacks on admins and similar malicious actions, not to discourage legitimate security research. -10. **Tools & Functions Code Execution Is Intended Behavior**: Open WebUI's Tools and Functions feature is **designed** to execute user-provided Python code on the server. This is core, intentional functionality, not a vulnerability. Function creation is restricted to administrators only. Tool creation is controlled by the `workspace.tools` permission, which is **disabled by default** for non-admin users and should only be granted to fully trusted users who are equivalent to system administrators in terms of trust. **Granting a user the ability to create Tools is equivalent to giving them shell access to the server.** More generally, **reports describing ANY attack chain that involves Tools or Functions, including but not limited to code execution, file access, network requests, or environment variable access, will be closed as not a vulnerability / intended behavior.** This applies to both direct code execution and frontmatter-based package installation (`pip install`). +10. **Tools & Functions Code Execution Is Intended Behavior**: Open WebUI's Tools and Functions feature is **designed** to execute user-provided Python code on the server. This is core, intentional functionality, not a vulnerability. Function creation is restricted to administrators only. Tool creation is controlled by the `workspace.tools` permission, which is **disabled by default** for non-admin users and should only be granted to fully trusted users who are equivalent to system administrators in terms of trust. **Granting a user the ability to create Tools is equivalent to giving them shell access to the server.** More generally, **reports describing ANY attack chain that involves Tools or Functions, including but not limited to code execution, file access, network requests, or environment variable access, will be closed as not a vulnerability / intended behavior.** This applies to both direct code execution and frontmatter-based package installation (`pip install`). Deployments that do not need Tools or Functions can set `ENABLE_PLUGINS=false` to disable plugin execution entirely. 11. **Legacy Code Paths Are Out of Scope**: Open WebUI maintains some code paths that are explicitly marked as **legacy** in the official documentation, which is authoritative as to what is legacy. Legacy paths remain available, sometimes still the default, purely for backwards-compatibility reasons, not because they are the supported or maintained surface. Security and functional work happens on the supported replacement, not the legacy path. Reports describing a security boundary issue **on a legacy code path that does not also reproduce on the supported replacement** are usually out of scope under this rule. We still want to hear about it if the issue reproduces on both the legacy path **and** the supported modern replacement, or if the legacy path is the only documented way to achieve a given function (no migration target exists yet). @@ -224,13 +224,13 @@ These scenarios represent **admin negligence** or **environment compromise**, no Open WebUI is designed for private, trusted networks and ships with defaults optimized for ease of setup. Production deployments handling sensitive data should review the [Hardening Guide](../getting-started/advanced-topics/hardening.md) for a comprehensive checklist. -A key consideration: **without Redis, signing out and password changes do not revoke existing JWT tokens**. They remain valid until they expire (default: 4 weeks). This means compromised tokens cannot be invalidated, and deactivating an account does not revoke the token already issued to it. For production deployments, either configure [Redis](../tutorials/integrations/redis.md) or shorten `JWT_EXPIRES_IN` to limit the window of exposure. See [Token Revocation](../getting-started/advanced-topics/hardening.md#token-revocation) for details. +A key consideration: **without Redis, signing out and password changes do not revoke existing JWT tokens**. They remain valid until they expire (default: 4 weeks). This means compromised tokens cannot be invalidated, and deactivating an account does not revoke the token already issued to it. Even with Redis, only sign-out, password changes and OIDC back-channel logout revoke tokens; role changes and account deactivation do not. For production deployments, either configure [Redis](../tutorials/integrations/redis.md) or shorten `JWT_EXPIRES_IN` to limit the window of exposure. See [Token Revocation](../getting-started/advanced-topics/hardening.md#token-revocation) for details. ## Product Security Process - Internal and periodic external reviews of our architecture and pipelines - Automated and manual testing for both front-end and back-end - Proactive risk management and code reviews as part of ongoing development -- Continuous improvements and integration of advanced tooling for static/dynamic analysis +- Monthly Dependabot updates across the Python, npm and GitHub Actions ecosystems; SAST and SCA scanning are planned If you have an immediate and actionable security concern, please create a report in our [security advisory portal](https://github.com/open-webui/open-webui/security/advisories) or [issue tracker](https://github.com/open-webui/open-webui/issues). diff --git a/docs/security/supply-chain-security/index.mdx b/docs/security/supply-chain-security/index.mdx index f586f5330f..4c32368759 100644 --- a/docs/security/supply-chain-security/index.mdx +++ b/docs/security/supply-chain-security/index.mdx @@ -12,7 +12,7 @@ If a database or scan report shows a CVE against Open WebUI, check whether the i ::: :::info The short version -None of the indicators these scanners raise against Open WebUI correspond to a named vulnerability, a CVE or confirmed malicious code. Most are automated behavioral heuristics that flag capabilities the software has by design. Some go further and publish alarming, unsubstantiated claims, most notably a "potential malware" banner, without identifying any specific file, function or line and without providing any evidence for the claim. No malicious code has been identified in Open WebUI. Because every published artifact is built from the public source in [open-webui/open-webui](https://github.com/open-webui/open-webui) and is reproducible from it, every one of these claims can be checked against the code directly. +None of the indicators these scanners raise against Open WebUI correspond to a named vulnerability, a CVE or confirmed malicious code. Most are automated behavioral heuristics that flag capabilities the software has by design. Some go further and publish alarming, unsubstantiated claims, most notably a "potential malware" banner, without identifying any specific file, function or line and without providing any evidence for the claim. No malicious code has been identified in Open WebUI. Because every published artifact is built from the public source in [open-webui/open-webui](https://github.com/open-webui/open-webui) and can be checked against it, every one of these claims can be checked against the code directly. ::: ## What these scanners measure @@ -46,7 +46,7 @@ Because Open WebUI's published packages are built entirely from the public sourc ### Dependency alerts and "obfuscated code" -These originate in transitive dependencies and in the pre-built, minified front-end assets bundled in the distribution. Minified JavaScript is routinely classified as "obfuscated" by scanners because it is not human-readable, but it is ordinary compiled front-end code, not hand-obfuscated logic in Open WebUI's source. Dependency alerts track the wider ecosystem and are handled through routine dependency maintenance. +These originate in transitive dependencies and in the pre-built, minified front-end assets bundled in the distribution. Minified JavaScript is routinely classified as "obfuscated" by scanners because it is not human-readable, but it is ordinary compiled front-end code, not hand-obfuscated logic in Open WebUI's source. Dependency alerts track the wider ecosystem and are handled through routine dependency maintenance: Python dependencies are exact-pinned with a lockfile, npm has its lockfile, and Dependabot runs monthly for four ecosystems. Container-image CVEs are a separate matter: those originate in the base image, are addressed by rebuilding on updated bases and are not part of the PyPI package scan discussed here.