Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/security/accepted-risks/agentic-application-risks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion docs/security/accepted-risks/auth-timing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
4 changes: 2 additions & 2 deletions docs/security/accepted-risks/llm-output-unpredictability.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
20 changes: 13 additions & 7 deletions docs/security/chat-data-privacy-and-encryption.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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**
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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:

Expand Down
6 changes: 3 additions & 3 deletions docs/security/security-policy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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).

Expand Down Expand Up @@ -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).
Loading
Loading