Vulnerabilities
The Tool That Was Missing from the Menu but Present in the Request: Open WebUI CVE-2026-45350
CVE-2026-45350 allowed an authenticated Open WebUI account to name restricted local tools or administrator-configured MCP connections in a chat request, letting the completion pipeline assemble capabilities the account was not permitted to use before Open WebUI 0.8.6 completed the server-side authorization repair.

In this article
1 The private tool returned to the chat through a field the menu never showed
Imagine an ordinary Open WebUI deployment used by two teams. An administrator has connected a remote service for the incident-response group and marked that connection private. A regular account opens a new chat. The private service is absent from every picker the account can see, so the interface appears to have done its job. The request still contains a place where a client can name tools. In the affected releases, knowing the identifier could be enough to carry that hidden resource into the completion pipeline. The screen said “unavailable”; the server assembled it anyway.
That small disagreement is the whole story of CVE-2026-45350. GitHub Security Lab reported the issue after reviewing Open WebUI v0.6.43. The project advisory lists all releases through 0.8.5 as affected, 0.8.6 and later as patched, and a CVSS 3.1 score of 7.1 High. The vector requires network access and a low-privilege authenticated account, with no separate user interaction. Its practical effect depends on what the selected tool can do and which identity a configured connection carries.
1.1 A filtered catalog was only a view of policy, not the policy decision
Open WebUI can present local Python tools and server-backed tools inside a chat experience. Visibility controls decide which resources a user should discover and use. A browser normally obtains a filtered list and renders only those entries. That is useful product behavior, yet it cannot authorize a later HTTP request. Browsers are programmable clients: developer tools, scripts, API integrations, captured requests, and alternate front ends can all construct fields without walking through the visible picker.
The public proof of concept made the difference concrete. An administrator created an external MCP tool, assigned it an identifier, supplied a URL and any required authentication, then marked it private. A low-privilege user sent an authenticated request to the chat completion API and supplied the private identifier in tool_ids. The advisory reports that the restricted tool was used despite its visibility setting. No administrator had to click the request, open the conversation, or approve the call.
An identifier is not a secret. Even when it is a random-looking value, it can survive in exported chats, browser storage, support screenshots, logs, configuration backups, shared prompts, API traces, copied examples, or deployment conventions. Authorization has to remain correct after the identifier is known. Treating obscurity as a second lock only changes how quickly the mistake is found; it does not convert a record lookup into an access decision.
The account was authenticated. That fact answers “who sent this request?” It does not answer “which tool records may this account read?” or “which connection may the service use for this account?” The vulnerable route accepted the first answer and moved ahead without establishing the second for every selected object. That missing object-level decision led the project to classify the defect as CWE-862, Missing Authorization, and explains why the CVSS vector uses PR:L instead of PR:N.
For defenders, the first useful mental model is a two-column ledger. The left column contains what the interface displayed. The right contains what the server resolved for the completion. A secure request produces a right column that is a subset of resources authorized at that moment. An affected request could contain a hidden ID on the right even though the same object was absent on the left. Historical review must reconstruct both columns; screenshots of the menu cannot prove what entered the model’s callable set.
That separation also keeps the finding precise. The advisory does not say every ordinary user automatically received every tool. A requester had to name a resource, the deployment had to contain that resource, and the completion path had to load it. Invocation then depended on the supplied prompt, model behavior, function-calling mode, and the available schema. These conditions narrow individual events without repairing the missing server-side decision.
The published CVSS vector provides a second precision check. AV:N/AC:L/PR:L/UI:N describes a network-reachable path with low attack complexity, a required low-privilege account, and no separate approving user. S:U/C:H/I:L/A:N estimates high confidentiality effect, limited integrity effect, unchanged scope, and no scored availability effect. A local deployment can rank a connection above or below that baseline after examining its real methods, yet the article should not silently convert a general score into evidence of a specific stolen record or modified system.
1.2 The consequence belonged to the selected capability, not to the chat box itself
A chat interface can make the issue look like a prompt-handling flaw. The vulnerable object was more powerful than text. A local tool record could lead Open WebUI to load Python functions, bind configuration values known as valves, turn function signatures into model-visible specifications, and retain a callable for later execution. An MCP connection could carry a remote URL, authentication mode, key material, and a catalog of methods exposed by another system.
The impact therefore changes from installation to installation. A demonstration tool that fetches a public document shows the authorization failure with low operational harm. A private tool that can search internal tickets, read a repository, query customer records, modify cloud state, or trigger a deployment carries the privileges of those actions. CVSS captures a general product-level estimate; an operator still has to inventory actual capabilities before deciding incident priority.
Schema exposure matters even when no call completes. Function names, descriptions, parameter shapes, and returned errors can reveal what an internal service offers. Execution is the larger concern because the model may choose a selected function and Open WebUI may call it. The public advisory states that authentication stored on the server could be used for the invocation, so the low-privilege web account and the remote service identity were not necessarily the same principal.
The model did not create the permission error. By the time a model received function specifications, application code had already selected which capabilities belonged in its environment. The model could decline to call a function, call it after an explicit prompt, or choose it during tool-enabled reasoning. None of those outcomes is a dependable access control. The only durable result is to keep a forbidden specification and callable out of the environment before inference begins.
This gives incident responders a disciplined way to phrase exposure. First establish that an unauthorized resource was resolved. Then establish whether its schema reached a completion. Then determine whether the completion emitted a tool call. Finally correlate that call with local side effects or the remote service’s audit records. Skipping directly from a requested ID to a claim of data loss would overstate evidence; stopping at “the menu hid it” would miss the server behavior the advisory proves.
The same sequence guides credential decisions. A stored token should not be rotated merely because a vulnerable version existed if logs prove the related connection was never configured or never reached. Rotation becomes urgent when an unauthorized request caused the connection to initialize, when remote audit records show an operation, or when logging is too weak to bound use. Capability, event, and evidence quality belong in the same decision.
Data classification should be attached to the capability before responders read thousands of chats. A tool that searches public manuals can sit in a lower tier. A connection that reads legal cases, payroll records, production repositories, or customer support exports belongs in a higher tier even if its methods are read-only. A tool with delete, merge, deploy, invite, or credential-management methods adds integrity concerns. This tiering does not decide whether exploitation occurred; it decides where evidence collection and credential containment start when time is limited.
Scoping has to retain two identities: the person who initiated the request in Open WebUI and the principal that performed the operation in the target service. Saving only the web account hides the authority of the remote token; saving only the service account makes unusual activity resemble normal integration traffic. Figure 1 separates those identities, and the source review and investigation that follow keep them joined as one event.
2 One authenticated request carried untrusted selections into trusted middleware
The source becomes easier to follow when the request is treated as a parcel with two labels. Authentication middleware attaches the verified user. The client supplies the requested model, messages, and tool selectors. process_chat_payload() receives both. From there, it builds metadata, resolves resources, prepares function definitions, and hands the resulting set into the later completion and execution stages. The flaw appeared where trusted identity and untrusted selection met.
This route performs much more than a database query. It is an assembly line: remove control fields from the incoming form, interpret identifiers, find local records or configured servers, obtain schemas, decorate callables with request context, merge them into a common dictionary, and expose that dictionary to a model. Each stage adds meaning. A missing decision near the beginning can therefore survive as executable authority near the end.
2.1 chat_completion authenticated the caller, while process_chat_payload() interpreted the caller’s object names
The affected API accepted an authenticated completion request. In the v0.6.43 source linked by GitHub Security Lab, the route forwards the request body and user into processing middleware. That verified user object contains the account ID and role used by later controls. Authentication is therefore present and meaningful. The defect was the absence of an object-specific read decision before the chosen tool became available.
process_chat_payload() removes tool_ids from the form data and preserves them in request metadata. Other metadata can describe server-backed tools. Removing the field is not validation; it is a transfer from the external request shape into the internal execution shape. After this transfer, logs that capture only the upstream provider request may no longer show the original selector. Application-level telemetry needs to record it before transformation.
The client controls the list’s membership and order. A request can contain one ID, several allowed IDs, a mixture of allowed and denied IDs, a server-form identifier, or a value that does not resolve. Robust authorization evaluates every resolved member separately. Rejecting only unknown values leaves known private objects exposed. Accepting the entire list after finding one valid member lets a permitted tool carry a forbidden neighbor into the same completion.
Direct API access is not exceptional behavior for this product. The advisory’s proof uses an API key enabled by an administrator and a regular account. That remains a low-privilege authenticated scenario under the published vector. Defenders should avoid dismissing it as a browser bypass because the security property is supposed to hold for any supported client speaking to the route.
The request also shows why prompt filtering cannot solve the issue. A policy could try to block words such as “private tool” or a known method name. The selector lives in a structured field, and a model may infer a call from ordinary language once the schema is present. Resource authorization has exact inputs—the user and the resource—and can make a deterministic decision. Natural-language screening has neither that precision nor complete coverage.
A useful trace point sits immediately after authentication and before tool resolution. It should capture request ID, user ID, role, selected local IDs, selected server IDs, chat ID, model, source address, and timestamp. Sensitive message text can follow separate retention rules. This compact event preserves the question the old path failed to answer and makes later joins with grant history possible.
Reverse proxies often record method, path, status, latency, and body size while omitting JSON bodies. Provider logs may see only the transformed completion after tool_ids has been removed from the top-level form. These are useful but incomplete views. Open WebUI is the one component positioned to record both the authenticated actor and the original selectors before transformation. A privacy-conscious event can hash chat and key identifiers, retain resource IDs needed for policy review, and exclude message content entirely.
Investigators should preserve three related shapes: the client’s original form, the metadata produced by middleware, and the function specifications sent to the model. The form records what the user requested; metadata records how the application interpreted it; the model payload records what was finally exposed. Carrying one request ID through all three reveals exactly where an identifier was accepted or removed and prevents a later field refactor from breaking the audit trail.
2.2 Local functions and remote methods converged into the same callable dictionary
Although the sources differ, the middleware normalizes them into one collection. A local Python function and a remote MCP method both need a name, description, parameter schema, and an execution adapter. Open WebUI stores these entries in a tools dictionary that downstream code can turn into OpenAI-style function specifications or another tool-calling format. Uniformity helps the product; it also means a forbidden entry becomes ordinary once inserted.
For local records, get_tools() resolves an ID through Tools.get_tool_by_id(), obtains or loads the module, applies global and user-specific valve values, inspects declared functions, and constructs callable entries. For server-backed records, middleware finds the configured connection, prepares authentication and a client session, obtains remote tool specifications, and wraps calls so a later selection reaches the server. The two branches meet before model use.
Function-name collision handling illustrates how fully resolved entries are integrated. The code can prefix a tool identifier when another function already uses the same name, then stores the adjusted entry in tools_dict. Once stored, downstream logic sees a valid callable with a unique key. It does not know that the originating request was unauthorized unless the resolver performed and recorded that decision first.
Tool-enabled completion has at least two implementation modes. A provider or model may support native tool calls, or application middleware may prompt a task model with serialized specifications and parse a chosen function. Both modes consume the assembled collection. Authorization tied to one model provider, one prompt template, or one parsing path would leave the other mode exposed. Enforcement has to occur where the resource enters the common collection.
Call results can become conversation content, citations, files, or embedded user-interface material. This makes post-call containment difficult. Even a read-only remote method may return sensitive text that the chat stores, streams, indexes, or exposes to later participants. A write-capable method may create effects outside Open WebUI that deleting the chat cannot reverse. Preventing entry is both simpler and more complete than cleaning up every possible result channel.
Streaming does not change that moment. A completion can emit partial text, a tool-call envelope, arguments in later chunks, and a final result across several events. The callable collection is still prepared before those chunks can reference a server-side function. Logging each streamed fragment without retaining the initial authorized set makes an investigation noisy and incomplete. Record the set digest and its per-resource decisions once, then link every later chunk and call to that digest.
Figure 2 follows that assembly line without assuming the model will call anything. The security-relevant moment is the population of the callable set. A denied object must disappear before schema serialization, module import, credential access, network initialization, or name-collision handling. “The model did not choose it this time” is an execution outcome, not evidence that access control worked.
3 The local-tool branch turned one database record into executable application behavior
The first branch begins with a compact lookup. A tool identifier reaches get_tools(); Tools.get_tool_by_id() retrieves the stored record. From there the application can load the associated module, combine its configuration with user context, inspect its declared methods, and publish callable specifications. A record that looked like one row in a workspace catalog was therefore the doorway to code running inside the Open WebUI process.
This branch also explains why an access check after model selection would arrive too late. Module resolution, configuration access, schema construction, and function registration occur while the callable set is assembled. A denied resource should not participate in any of those stages. The March refactor identified by the project advisory moves the read decision ahead of module loading, giving the resolver a simple rule: no authorized read, no tool object in the result.
3.1 get_tool_by_id() answered existence, then the old resolver treated existence as eligibility
The affected model method is deliberately uncomplicated. Given an ID, it obtains a database session, asks for the matching Tool, and converts the row into a ToolModel. That is appropriate for an internal storage primitive. It answers whether the object exists and returns its fields. It does not know the requesting account, its groups, or the permission needed by a particular operation.
The old resolver called that primitive while processing client-supplied IDs. In the path documented by GitHub Security Lab, there was no ownership comparison or equivalent read test before the returned record advanced. The caller’s verified user was available to the surrounding function, so the missing input was not identity. The missing step was a policy evaluation that joined identity with this exact record.
Existence checks and authorization checks fail differently. A nonexistent ID can be skipped or reported as missing. A forbidden existing ID should be excluded while avoiding details that help enumerate private records. If both cases produce the same externally visible result, internal logs can still distinguish “unknown” from “denied” for investigation. That split protects privacy without sacrificing operational evidence.
Once the record advanced, the resolver sought a module in the application cache and could load it by tool ID when absent. Python module loading may initialize objects and evaluate module-level statements before any advertised method is selected. The advisory’s confirmed impact is unauthorized tool use; defenders do not need an additional unproven side effect to conclude that loading a forbidden module is placed on the wrong side of the decision.
The resolver then prepares special parameters such as the current user and request-scoped helpers. It can load stored valves for the tool and user valves associated with the account. These values may contain service settings, targets, or operational choices expected by the function. What enters the request is therefore not a neutral reflection of source code. It is a configured callable placed inside an authenticated request’s live context.
Function inspection converts methods into specifications with names, descriptions, and permitted parameters. If two tools advertise the same method name, code can prefix an identifier until the dictionary key is unique. This collision handling is evidence that the selected record has already become a first-class participant in execution. Authorization belongs before all of that normalization, because downstream consumers cannot recover the original visibility decision from a renamed function.
The affected path therefore crossed four distinct states: named object, retrieved record, loaded and configured module, model-callable entry. Investigators should preserve those states separately when logs allow. A request containing an ID proves the first. A resolver event proves the second. import or cache telemetry supports the third. A serialized specification or tool-call record supports the fourth. The stronger conclusion should follow the strongest observed state.
Function specifications and callable execution also deserve separate probes. A name, description, and parameter schema may already have been serialized for the model even though the Python callable never ran. In another application-managed mode, the server may select and invoke the callable directly. A regression fixture should mark specification construction and function entry independently so “the model saw it” and “the function ran” never collapse into one claim.
3.2 The local repair asks about role, ownership, group membership, and read permission before loading code
Commit 9b06fdc8fe1c933071610336be05f11e77e6c8eb changed the order. The resolver obtains the requesting user’s group IDs, retrieves each named record, and checks three allowed routes. An administrator may pass when the deployment enables BYPASS_ADMIN_ACCESS_CONTROL. The record owner may pass. Another account must satisfy the tool’s read-access policy through has_access() with the current group set.
If none of those routes succeeds, the fixed code writes an access-denied warning and continues to the next ID. It does not load the module, set valves, inspect functions, or place a callable into the result. “Continue” is important in a mixed request: one denied item does not authorize its neighbors, and one allowed item does not inherit denial. Each object receives its own decision.
Ownership and sharing remain separate concepts. The owner can use the object because the record says who created or controls it. A group or user grant can extend read access without changing ownership. Administrator bypass is a deployment policy with an explicit configuration switch. Collapsing these cases into a single “visible” Boolean would make audits harder because responders could not explain why a request was permitted at a specific time.
Group membership must be evaluated against the request timestamp. A current database snapshot can misclassify an event after people change teams. The same applies to a tool’s access-control document and owner. Useful audit evidence includes versioned group assignments, grant changes, object updates, administrator-policy changes, and the exact code release that evaluated them. Without history, a present-day “has access” result cannot settle a past request.
The patch’s placement protects every completion path that uses get_tools(). It also reduces dependence on the catalog endpoint. A new interface can forget to filter a menu, and a custom API client can send raw IDs, yet the final resolver still enforces the object’s policy. Central placement is especially valuable in AI middleware because providers, prompt templates, and tool-calling modes can change while the resource decision remains the same.
Backports should preserve behavior, not only copy a few lines. A branch may store group IDs differently, use another access-control shape, cache modules at another layer, or rename the resolver. The acceptance conditions remain testable: denied local IDs produce no callable entries; no denied module is loaded on that request; owned and explicitly shared tools still work; group removal takes effect on a subsequent authorization decision; the configured administrator posture is honored deliberately.
Cache behavior needs two separate assertions. A module cached by an authorized request may remain in process memory for performance, but a later unauthorized request must still fail before that cached object is added to its callable dictionary. Conversely, denying one account must not evict or corrupt the module for an authorized account. The policy protects use, while the cache manages object lifetime. Treating “already loaded” as “already authorized” would recreate the same mistake with a faster code path.
A code review can also search for sibling entry points that bypass the repaired resolver. Listing, editing, deleting, importing, and executing tools are different operations and may have their own routes. CVE-2026-45350 concerns selection through the chat completion pipeline. Reviewing adjacent routes is a defensive completeness check, not evidence that those routes share the published flaw. Any separate defect would require its own confirmation and handling.
4 The MCP branch borrowed an administrator-configured identity for a user-selected destination
The remote branch raises the stakes because the selected object is a connection, not only a function catalog. Open WebUI can hold a server URL, connection type, authentication mode, key material, per-connection configuration, and access grants. During chat preparation it can contact the server, enumerate available methods, translate their schemas, and create adapters that later invoke those methods. The request chooses the connection; the application supplies the stored reach.
GitHub Security Lab’s demonstration used a public fetch server so the authorization failure could be observed without exposing a private system. The same application path can point at any administrator-configured MCP service. The advisory therefore states the impact in capability terms: restricted tools could be invoked, and server-stored authentication could be used. It does not claim every deployment exposed the same data or allowed the same write operations.
4.1 Connection lookup happened before authentication fields, network setup, and remote schema discovery
A server-form identifier tells middleware which configured connection to locate. The code searches the connection collection for the corresponding ID. A missing object can be logged and skipped. A found object contains the information needed for the next phase: server type, URL, authentication mode, credentials or session behavior, enabled methods, and connection configuration.
The dangerous sequence begins when a found record is treated as eligible. Authentication headers can be assembled from the record. An MCP client can be created and initialized against the URL. The client can request the server’s tool catalog. Each returned definition can be filtered, normalized, and wrapped so a later tool call sends arguments to the same server. By then the low-privilege account has influenced a network session established with application-held connection material.
MCP separates discovery from invocation. A client uses the tools capability to learn names, descriptions, and input schemas, then sends a call for a chosen name and arguments. That separation yields two observable milestones. A successful list operation proves that Open WebUI reached the remote service under some connection context. A successful call proves that a method ran. Remote audit records should preserve them distinctly because a list with no call has different consequences from a data-changing method.
The stored key need not appear in the chat response to be security-sensitive. A confused service can apply a credential on behalf of the wrong web user while keeping every token byte hidden. What matters is authority use: which principal the remote service recognized, which methods that principal could access, and which objects those methods touched. Secret-scanning the conversation is useful for other incidents but cannot detect this form of delegated use by itself.
Network controls add another layer of reach. The Open WebUI server may connect to internal names and addresses unavailable from the user’s workstation. A configured MCP service may in turn reach source control, ticketing, storage, or orchestration APIs. CVE-2026-45350 does not create those integrations; it can let the wrong authenticated account select one that already exists. Incident scoping should begin with actual connection inventory and remote audit logs, not a generic list of systems MCP could theoretically access.
Errors are evidence too. A denied method at the remote server can reveal that the connection initialized and that a call was attempted, while limiting final impact. A timeout may show only a network attempt. A schema response proves discovery but not a call. A returned object identifier, remote audit event, or downstream change provides stronger execution evidence. Classifying these outcomes prevents both false reassurance and unsupported escalation.
The correct decision point sits directly after connection lookup and before the first sensitive field is consumed. At that moment the application has the requesting user and the connection’s access-grant configuration. It can allow or skip deterministically. Moving the check later—after reading the key, opening a socket, or listing methods—would reduce some calls but still expose operations that a denied account should never trigger.
A per-connection method filter is a useful second control but cannot replace connection authorization. It can remove high-impact methods from an allowed user’s catalog or narrow what a shared integration offers. It does not answer whether this user may discover or use the connection at all. Regression should therefore assert two nested sets: first the account’s authorized connections, then the permitted methods within each allowed connection. A method filter applied to a forbidden connection has already accepted the wrong outer object.
The MCP authorization specification describes how a client and server obtain and use a token. Open WebUI still has to decide which web user may activate which configured client. Protocol authentication proves the connection’s identity to the remote service; application authorization decides whether the local account may borrow that connection. A correct result at either layer does not establish the other.
4.2 The remote service saw the connection principal, so response teams must correlate two audit worlds
Open WebUI identifies the initiating account. The MCP server may identify only the bearer or other credential attached to the configured connection. Without correlation, the remote log can look like routine activity by a trusted integration. This is the operational trap: the upstream actor and downstream principal differ, yet both describe the same event. A shared request or trace ID is the cleanest bridge when both products can record one.
Where no shared ID exists, responders can join on time, destination, method, argument fingerprint, response size, chat ID, and source host. Clock synchronization matters. Streaming completions and retries can spread one interaction across several seconds or produce repeated list and call operations. Preserve raw timestamps with time zones and measured clock offset before converting them into a single incident timeline.
The connection’s capability set should be captured at the event date. Remote servers evolve: methods are added, descriptions change, and tokens gain or lose roles. Today’s tools/list response may not match what an affected request received. Configuration backups, deployment commits, MCP server releases, and audit metadata can reconstruct the earlier catalog. If that history is unavailable, state the uncertainty instead of treating the current catalog as historical fact.
Arguments deserve careful handling because they may contain secrets or regulated data. Preserve hashes and selected metadata where full payload retention is prohibited. For a repository method, record organization, repository, operation, object ID, and result status. For a ticketing method, record project, issue ID, operation, and attachment count. The goal is to establish action and scope without duplicating sensitive content into an investigation system.
Credential rotation follows from observed or unbounded use. Replacing an MCP token closes future sessions but does not undo actions that already succeeded. Review downstream object history, access grants, webhook deliveries, exports, and secondary credentials the tool could read. If the remote service lacks adequate audit logs, the absence of records lowers confidence; it does not prove that the affected path stayed idle.
Least privilege limits the radius before and after patching. A read-only search connection should not share an identity with a write-capable automation. Separate connections can have separate grants, tokens, destinations, and alerting. Short token lifetimes, destination allowlists, method filters, and explicit per-group sharing reduce the authority available to any one selection. These controls complement the product fix; they do not make 0.8.5 safe.
Rate limits and remote approval workflows can reduce damage after a call begins, but their logs remain part of the evidence. A remote service may reject the sixth request, require approval for a write, or allow search while denying export. Each result changes realized impact without changing the upstream authorization failure. Capture accepted and rejected methods, because a series of denials can still prove that an unentitled account drove the stored connection far enough to attempt protected operations.
The scene from the opening can now be replayed accurately. The regular account supplies a private connection ID. Affected middleware finds the record, applies the stored connection identity, learns the remote methods, and offers them to the completion. The repaired path evaluates the account against the connection first. A denied account never reaches authentication parsing, client initialization, method discovery, or call wrapping.
With bearer authentication, the remote log will usually name the principal behind the stored token. Other supported authentication modes change the available fields, but the investigation still asks the same pair of questions: which Open WebUI account initiated the session, and to whom did the target attribute the action? The response playbook for every important connection should name the remote log location, principal, retention period, and owning team before an incident makes those details urgent.
5 Two repair histories meet at one operational floor: Open WebUI 0.8.6
The public record contains two clocks that are easy to flatten into one. Commit 9b06fdc8fe reorganized tool resolution and added authorization logic before the v0.7.0 release on January 9. Commit 4737e1f118 later introduced a generalized connection-access helper used by the MCP resolution loop in the v0.8.6 line released March 1. The project advisory published in May maps local tool records to the first repair and the exact administrator-configured MCP proof to the second.
For operations, the advisory settles the version question: releases through 0.8.5 are affected, and 0.8.6 or later is the complete patched floor. Source history still matters because private forks and distribution packages may carry selected commits without adopting the tag. A trustworthy backport must show both resource families enforcing access before privileged work, along with the data-shape migration expected by its branch.
5.1 The v0.7.0 refactor made access part of local resolution, yet the later MCP path still needs independent proof
The March-named commit in the advisory history is broad despite its short subject, “refac.” Its diff moves local tool construction into a clearer loop, obtains group membership, evaluates ownership and read access, and introduces a helper for server connections. It also places server checks before authentication fields in the code changed at that moment. These facts are visible in the commit and useful for downstream review.
The project advisory nevertheless assigns distinct fixed releases. It says local Tool records were first fixed in v0.7.0 and the administrator-configured MCP server form used by the published proof was first fixed in v0.8.6. Operators should preserve that distinction. Finding a helper with a reassuring name in an intermediate branch is weaker evidence than exercising the exact request shape against the shipped build.
Product architecture changed between the tested v0.6.43 source and v0.8.6. Tool-server connection data, native tool support, terminal integrations, and shared access utilities evolved. A check can exist in one resolver while another representation or route still needs the same policy. This is a common reason security advisories name a release floor instead of asking users to infer safety from an isolated diff.
Acceptance has to reach the replicas that actually answer completion requests. Record package version, image digest, repository revision, local patches, process start time, and serving pod or host. During a rolling upgrade, drain old replicas, admit the new digest only after readiness and paired allow-and-deny checks, and verify that stale workers have exited. A downloaded image, updated tag, or patched repository is not evidence about the running process.
For a private backport, retain the parent commit and an explanation of the branch-specific difference. Trace backward from the denial-side continue to the user and policy inputs, then forward to confirm that credentials and network work remain untouched, and prove that order at runtime. If another regression forces a rollback below 0.8.6, disable high-impact tools, remove stored credentials, or restrict the completion endpoint; hiding the catalog again is not a security rollback plan.
5.2 The v0.8.6 helper unified connection grants and put the decision before credential use
Commit 4737e1f11847d057859ec78892fa89e24cbcd83b adds has_connection_access() to the shared access-control utility. The helper accepts the current user, a connection dictionary, and optionally a precomputed group set. An administrator can pass under the configured bypass policy. When config.access_grants is empty or missing, the connection is treated as available to all users. When grants exist, has_access() evaluates read permission for the account and its groups.
That empty-grant behavior is important during remediation. “No grants” is not automatically private in this data model. To restrict a connection, administrators need a meaningful access-grant configuration and must verify it through a non-member account. A migration that drops or misnames the field can turn an intended restriction into open access even though the code is patched.
The same commit contains migrate_access_control(), which can translate older access-control keys to the newer access-grants shape. Backports and upgrades should validate persisted connection objects after migration, especially where configuration has passed through environment variables, database rows, JSON exports, or an administrative interface. The resolver can evaluate only the policy data it actually receives.
Middleware switches from the earlier tool-server-specific helper to has_connection_access(). The denial branch logs the server ID and user ID, then skips before authentication type is read and before the client path proceeds. This order is the security property operators can observe. The name of the helper is secondary; the trace must show a denied decision preceding key access, DNS, socket activity, initialization, discovery, and call wrapping.
Generalizing the helper also reduces drift among connection-backed features. Tool servers and terminal servers can share the same grant semantics while keeping their separate execution logic. Shared policy code is valuable only when every sensitive caller invokes it early. Code search should enumerate all reads of connection URLs, keys, and access-grant fields, then confirm that each reachable operation performs the common decision.
Upgrade testing should include open and restricted connections. An empty-grant connection should remain intentionally open if that is the administrator’s design. A user grant and a group grant should permit access. A non-member should be denied. Administrator behavior should match BYPASS_ADMIN_ACCESS_CONTROL. These cases detect both accidental lockout and accidental exposure during data migration.
The v0.8.6 release notes primarily describe product features, while the later security advisory provides the authoritative affected and patched mapping. That publication order is normal for a coordinated issue whose security explanation arrives after code and release. Operators should use the advisory for security status, the release tag for package provenance, and commits for implementation review. None of the three sources alone answers all three questions.
The safest release statement is therefore concise: use 0.8.6 or later, restart every serving process, confirm the deployed digest, and prove the local and MCP paths independently. Commit presence helps explain a backport; it does not replace runtime evidence. Figure 5 keeps the two source histories separate until they meet at that acceptance point.
6 A useful regression watches what never happens after a denied selection
A status code alone cannot prove this repair. The completion endpoint may return a normal response after silently omitting a forbidden tool, and a downstream provider may fail for unrelated reasons. The decisive assertions concern absence and order: the denied resource is absent from the callable set, its code or credentials are untouched, and no network side effect begins. Allowed resources in the same test must still complete, proving that the harness reached the correct branch.
The test environment should be small enough to explain and rich enough to cover policy. Two ordinary users, one administrator, two groups, one owned tool, one directly shared tool, one group-shared tool, one private tool, one open MCP connection, and one restricted MCP connection form a practical baseline. Every object needs a stable identifier, and every sensitive operation needs an observable counter or trace marker.
6.1 Local regression proves exclusion before import, configuration, and schema construction
Begin with a harmless local fixture whose module reports when it is loaded, whose valve accessor reports when configuration is read, and whose function reports when it is called. The function can return a constant. The purpose is not to emulate a dangerous integration; it is to reveal execution order. Reset all counters before each request so one permitted test cannot contaminate the denied case.
Send an authenticated completion request that names the private fixture from a non-owner account. The response may be an ordinary model answer, so inspect server-side state. The expected result is a denial event for that user and tool ID, no module-load increment, no valve access, no function specification in the serialized tool set, and no call. If the module was already cached by another test, use a cache-independent hook around resolution or run the denied case in a fresh worker.
Repeat with ownership, a direct read grant, a matching group grant, and the configured administrator policy. Each allowed case should produce the specification and permit a controlled call when the prompt and model are deterministic. Then revoke the grant and issue a new request. The next resolution should deny it. Long-lived conversations must not turn yesterday’s callable set into a permanent capability after policy changes.
Mixed lists are essential. Submit an allowed ID before a denied ID, reverse the order, include two denied IDs, and add an unknown ID. The output should contain exactly the authorized subset. No item should inherit the previous item’s result, and an exception for one malformed identifier should not accidentally restore the original unfiltered list. Record per-object decision reasons to make this visible.
Function-name collisions provide another negative case. Configure an allowed and a denied tool with the same advertised method name. The denied entry must vanish before collision handling. A prefix derived from its identifier must not appear in the callable set, logs intended for the user, or provider payload. This proves that exclusion occurs before normalization has obscured the source object.
Test both native function calling and application-managed function selection where the deployment supports them. The expected tool set should be identical because both modes consume the same authorization result. Provider failures, model refusals, and prompt differences are outside the permission assertion. Inspect the assembled specifications directly so a model’s choice cannot hide a resolver regression.
Concurrency deserves a controlled case. Run an authorized and denied request for the same cached tool at the same time, then alternate them across workers. The allowed request may use the module; the denied request must receive no callable entry even if cache population races with its resolution. This test protects the distinction between global implementation cache and per-request permission, a distinction that single-threaded unit tests can accidentally hide.
Browser automation is supplementary evidence. The failed property was the server accepting a client-controlled selection, so the security regression must construct the API request directly, supply the tool identifier, and inspect server-side results. A browser case can confirm that the menu still renders correctly, but it cannot stand alone; otherwise a future resolver regression can hide behind an interface that continues to conceal private entries perfectly.
6.2 MCP regression fails before key access, DNS, sockets, initialization, and tools/list
The remote fixture needs an instrumented connection object and server. Wrap access to the authentication field, name resolution, client construction, session initialization, list operation, and call operation with separate counters. A denied request should increment only the authorization decision. Even contacting a mock server is too late for that case; the absence of network activity is one of the properties under test.
For an open connection with empty grants, verify the documented allow behavior deliberately. For a restricted connection, test a direct user grant, matching group grant, non-matching group, revoked membership, and administrator bypass on and off. Capture the access-grant object used by each decision. A migration test should load an older configuration shape, run the project’s migration behavior, and confirm the resulting semantics.
A permitted call should establish the positive sequence: allow, read authentication mode, obtain credential material, initialize the client, list tools, expose the selected specification, and make a controlled call. The trace provides a reference against which the denied path can prove its early stop. Keep the fixture method harmless and return a unique request token so retries are easy to identify.
Test discovery without invocation. Permit the connection, list its methods, then configure the model or harness not to call one. This distinguishes remote reach from method execution. Next allow one controlled call and verify the remote audit record contains the expected connection principal, method, arguments, and correlation token. These two cases train both automated assertions and investigators to avoid merging separate milestones.
Exercise failures after authorization: invalid credential, unreachable host, initialization error, list failure, unknown method, and remote denial. They should be reported as connection or tool failures, not authorization successes or denials. The permission event remains successful because the user was allowed to attempt the connection. Clear classification stops reliability incidents from being counted as blocked attacks.
Multi-worker tests should alternate requests across replicas during and after a rolling upgrade. Every worker must deny the restricted selection before key access. Include a worker with an intentionally stale build in a quarantined test environment to prove that routing and version telemetry identify it. Once production rollout completes, no response should come from the stale digest.
Fail-closed behavior also needs an explicit definition. If group lookup or grant parsing raises an error for a restricted connection, the request should not proceed with stored credentials merely to preserve availability. At the same time, malformed policy should generate an operational signal that distinguishes it from an ordinary denial. Test this case with a controlled invalid grant object and confirm that the trace stops before connection work while operators receive enough context to repair configuration.
Remediation tests must distinguish a successful denial from a failed system. A denial carries an explicit access decision and leaves every sensitive counter at zero. A database, group-service, or parsing failure may also stop processing but offers no trustworthy policy result. Treating every exception as proof of enforcement both breaks legitimate use and overstates the control. Assert decision type, error category, and side-effect counters together.
Add time-sensitive rows for a grant revoked before a request, after resolution but before invocation, and after a connection has opened. The published fix guarantees the decision at resource resolution; the surrounding design still has to define what happens to work already in flight. Record the actual semantics and make high-impact operations conform to organizational policy so a session cache cannot defer revocation indefinitely.
Every run should retain a comparable digest of the authorized set. If allowed members change across an upgrade, the report must identify whether the difference came from the repair, a policy migration, or an unintended regression. Verifying only that denied items disappeared can miss legitimate tools removed by mistake; verifying only that allowed items still work can miss a private neighbor that remains present. Set-level comparison protects both properties.
7 Investigation begins with the capability inventory, then walks each request downstream
Patching answers what can happen next. Incident review asks what happened before the upgrade. The answer cannot come from a version string alone. An affected installation with no private tools has a different history from one that connected an administrative service. An installation with restricted resources still needs evidence that a regular account named, resolved, discovered, or invoked them. The investigation should move from inventory to requests to side effects in that order.
Preservation and remediation can proceed together. Snapshot relevant configuration, grant tables, group membership, application logs, reverse-proxy records, chat metadata, container identity, and remote service logs before retention or upgrades remove them. Then deploy the fixed build and reduce exposed authority. Keeping a vulnerable worker alive solely to reproduce the flaw adds risk and is unnecessary when source and public advisories already establish the mechanism.
7.1 Reconstructing one event requires the request, historical policy, callable set, and downstream result
Start by exporting every local tool and connection that existed during the affected period. For local tools, record ID, owner, creation and update times, module revision or hash, function names, access policy, global valves, and security-relevant capability. For connections, record ID, server type, URL, authentication mode, grant configuration, credential owner, remote principal, method allowlist, and the systems reachable through that principal.
Build a historical policy view. Group membership, direct grants, object ownership, administrator-role changes, and BYPASS_ADMIN_ACCESS_CONTROL can all change. Database audit tables, identity-provider logs, configuration repositories, backups, and administrative events may supply the timeline. If only current state exists, mark past authorization as unresolved; do not silently apply today’s membership to a request from months earlier.
Next extract chat and proxy events. Useful fields include timestamp, request ID, user ID, API key ID, chat and message IDs, source address, user agent, model, tool-choice mode, requested IDs, response status, duration, and serving revision. Some affected versions may not log selectors directly. Chat metadata, stored request bodies, tracing systems, provider payloads, and error messages can partially recover them.
For each named object, assign the strongest observed stage: requested, found, authorized under historical policy, resolved into the callable set, discovered from a remote server, selected by the model, invoked, returned data, or caused a verified side effect. Keep “authorized under historical policy” separate from “the vulnerable build failed to check.” A user might have legitimately held access even when the code path lacked enforcement.
Local execution evidence can include application logs, function-specific audit records, process creation, filesystem access, database queries, outbound connections, generated files, and tool-return citations. The tool implementation defines which signals matter. Preserve module hashes because names and methods may have changed since the event. A current benign version cannot establish what an older revision did.
Remote evidence includes DNS and proxy records, firewall flows, MCP server logs, identity-provider token use, method audit entries, accessed object IDs, exports, writes, and webhook deliveries. Correlate with a time window that accounts for streaming and retries. When one stored principal serves many Open WebUI users, remote logs alone may not identify the initiating account; the application request supplies that missing attribution.
Look for patterns that raise priority: regular accounts naming IDs absent from their catalog, repeated unknown or denied IDs, bursts across sequential identifiers, access immediately before sensitive remote methods, unusual data volume, calls near grant changes, and activity from API keys that had little prior tool use. These are investigation leads, not standalone proof of exploitation. Confirm them against resource and downstream evidence.
Document negative evidence with its coverage. “No matching calls in 30 days of complete MCP audit logs” is useful. “No evidence found” without sources, retention, clock range, and known gaps is not. If application logs omit selected IDs or remote logs omit arguments, state how that uncertainty affects credential rotation and notification decisions.
A simple confidence scale helps readers compare findings. “Confirmed request” requires a selector tied to an account. “Confirmed resolution” adds callable-set or discovery evidence. “Confirmed invocation” adds an application or remote call record. “Confirmed effect” adds the accessed object, returned data, or state change. “Possible” should identify the missing link. This vocabulary lets legal, privacy, engineering, and service owners act from the same timeline without turning every vulnerable request into a claimed compromise.
7.2 Response removes vulnerable code, shrinks stored authority, and leaves a verifiable trail
- Prove the serving build. Record every replica, digest, revision, process start time, and route that handles chat completions.
- Upgrade and restart. Move all workers to Open WebUI 0.8.6 or later and verify the local and MCP denial traces on the deployed package.
- Inventory capability. Map each local function and remote method to owner, grants, credential, destination, data class, and write authority.
- Preserve history. Export chat metadata, request and proxy logs, tool revisions, grants, groups, connection configuration, and remote audit records.
- Reconstruct per object. Grade each selected ID from request through resolution, model selection, invocation, response, and downstream effect.
- Contain identities. Revoke exposed sessions or accounts, rotate connection credentials where use is observed or cannot be bounded, and review downstream changes.
- Reduce standing privilege. Separate read and write connections, narrow tokens and method sets, restrict egress, and grant high-impact tools to specific groups.
- Retain acceptance evidence. Save regression traces, migration results, final digests, restart proof, and denied/allowed samples for future audits.
After restoration, monitor decisions as first-class security events. A useful record names requester, resource ID and type, owner, relevant groups, grant source, result, reason, serving revision, and correlation ID. Alert on repeated denied selection and on sudden sharing of high-impact connections. Keep content logging separate so privacy controls do not force the loss of authorization telemetry.
The response is complete only when operators can answer four questions with evidence: which vulnerable workers served traffic, which restricted capabilities existed, which accounts reached each capability, and what downstream identities did. “Upgraded” closes the code path. The remaining answers close the incident.
External notices, compliance reports, and customer communications should use the same evidence scale. An affected version is a product fact. The capabilities configured by this organization are asset facts. A selector, invocation, or returned object tied to an account is an event fact. Keeping the three categories distinct acknowledges vulnerability without presenting possible access as confirmed loss.
Closure criteria should name unresolved items. If a remote system has already aged out its audit trail, record which methods and objects remain unknowable, the conservative rotation performed, residual business risk, and the approving owner. Where evidence is complete, retain the query and result summary. A documented unknown is more useful than “nothing suspicious found,” and it gives future evidence a precise reason to reopen the case.
8 A model may choose among capabilities; it cannot decide which capabilities a user owns
CVE-2026-45350 is specific to Open WebUI, yet its design lesson reaches any application that assembles tools for a model. The callable environment is a security-sensitive object. Adding one function can expose a schema, load code, read configuration, open a connection, apply a credential, or enable a write. The environment must be derived from the authenticated principal and current policy before it is serialized for inference.
Human confirmation cannot repair the missing permission check. Some tool calls may require confirmation for product or safety reasons, but the public proof needs no administrator approval and the CVSS vector records no user interaction. A confirmation shown to the same unauthorized account would only ask that account to approve authority it never held. Permission comes first; optional confirmation can follow for sensitive allowed actions.
8.1 Every new connector should preserve five invariants from selection through result handling
The first invariant is server-side selection. The client may suggest IDs, names, or capabilities, but the server computes the authorized subset. UI lists can improve usability and reduce mistakes; they cannot expand that subset. Unknown and denied objects should fail safely without revealing private metadata, while internal telemetry records enough detail for investigation.
The second invariant is decision-before-use. Authorization precedes module loading, secret access, network resolution, client initialization, schema discovery, function registration, and execution. This ordering makes denial cheap and observable. It also creates a clean regression target: none of the later counters moves when the decision is false.
The third invariant is identity continuity. Every downstream action remains attributable to the initiating user even when a service credential performs it. Carry a correlation ID across completion, discovery, tool call, remote method, and result. Record the connection principal beside the user principal. If the remote protocol cannot carry the user identity safely, retain the mapping in trusted application telemetry.
The fourth invariant is policy freshness. Ownership, groups, grants, roles, and connection configuration can change during a conversation. Cache performance must not turn a revoked tool into a session-long capability. Define when access is reevaluated, how caches are invalidated, and how long an already-started remote call may continue. High-impact writes may need a second decision close to execution.
The fifth invariant is result containment. Authorized execution can still return sensitive data or create files, citations, and embeds. Apply output classification, conversation sharing rules, retention, and redaction after the call. This control addresses legitimate tool use and is separate from CVE-2026-45350’s missing selection check. Keeping the two concerns distinct makes tests and incident conclusions clearer.
Connector reviews can express these invariants as a capability ledger. For every resource type, name the client-controlled selector, authoritative record, policy data, first privileged side effect, downstream principal, result channels, and audit events. A blank cell reveals a design question before code ships. The same ledger supports threat modeling, implementation review, testing, and response documentation.
Performance optimizations must preserve the same ownership of decisions. Caching a remote schema can avoid repeated discovery, yet a cached schema should be attached only after the current user passes access. Prewarming a connection can improve latency, yet it should not let an unauthorized request trigger or inherit that session. Batch resolution can reduce database queries, yet its output still needs a per-object allow result. Fast paths are safe when they cache data and recompute permission at the documented freshness point.
8.2 The repaired opening scene ends with an empty slot where the private tool once appeared
Return to the regular account at the start of the story. It sends the same chat request and names the same private connection. On a fixed deployment, middleware retrieves enough connection metadata to evaluate access, sees that the account has no matching grant, logs a denial, and skips the object. The stored authentication is untouched. No MCP client opens. No remote schema enters the completion. The model receives no callable entry for that service.
An authorized incident responder sends the same request under a matching group grant. The decision passes, the connection initializes, allowed methods are discovered, and a controlled call can proceed. Both outcomes are necessary. Security is not achieved by disabling every tool; it is achieved by making the callable environment match policy for each account and each request.
Release acceptance should preserve those paired traces for both local and MCP resources. The denied local trace ends before module loading. The allowed local trace reaches a harmless function. The denied MCP trace ends before key access and network setup. The allowed MCP trace reaches a controlled server method. Every trace records build digest, user, resource, decision reason, and timestamp.
The reviewed public sources support a high-severity authenticated authorization bypass with potential confidentiality and limited integrity impact. They do not establish a universal remote-code-execution outcome, an availability impact, a specific enterprise compromise, or exploitation in the wild. Local capability inventory and event evidence determine whether a particular deployment experienced more than the published mechanism.
This evidence limit changes how teams communicate. The vulnerability notice can name the affected range, request path, authorization failure, stored connection authority, and fixed release with high confidence. An internal incident report can add the organization’s configured methods, affected accounts, calls, and objects when logs support them. Public statements should not borrow severity from hypothetical high-impact tools that were never configured, while private response should not ignore a powerful configured tool merely because the advisory used a harmless fetch service for demonstration.
For teams starting late, the shortest responsible path is still concrete: upgrade every worker to 0.8.6 or later; verify both checks in the running package; inventory local tools, MCP connections, stored identities, and grants; preserve historical requests and policy; correlate remote audit records; rotate credentials where use is observed or cannot be bounded; and keep per-object authorization telemetry after recovery.
For maintainers, the lasting artifact is the ordering contract. Identity arrives with the request. Policy is evaluated for each named object. Only allowed resources may load code, expose schemas, read credentials, open connections, or execute. Results then pass through their own data controls. New tool types can change protocols and user experience without changing that sequence.
The original visual mismatch—private in the menu, present in the server—disappears when the server becomes authoritative. The menu and request may still differ because clients can send anything. The callable set no longer follows the client’s claim. It follows the account’s actual permission, which is the only version of “available” that can safely reach the model.
That final state is measurable. A request can name any string. The resolver produces a set whose members each have an allow reason. Every credential read and tool execution points back to one of those decisions. A denied object leaves only a denial event and no privileged side effect. Once those statements hold across local tools, MCP connections, replicas, migrations, and revocations, the private cabinet in the opening scene is private in the only place that matters: the running server.
Research record
9Evidence, objects, and sources
The material below preserves the identifiers and references used in this report.
9.1Research objects
Products, actors, techniques, affected objects, and control points discussed in the report.
Open WebUI chat completion restricted-tool authorization bypass
Affected range in the project advisory
Complete project-advised fixed floor
Authenticated completion route carrying tool selectors
Local-tool owner, group, and read-access enforcement
Connection access enforcement used by the v0.8.6 MCP path
9.2Event chronology
- Private report submitted
GitHub Security Lab records the issue as reported through the project vulnerability-reporting process.
- Version 0.7.0 released
The first release named by the advisory for the local-tool record repair became available.
- Version 0.8.6 released
The release later identified by the project advisory as the complete patched floor became available.
- Project advisory published
The coordinated disclosure timeline records publication of GHSA-4pcg-253r-rf9w.
- GitHub Security Lab analysis published
GHSL-2026-002 documented the request fields, missing check, and downstream stored identity.
- SOSEC source review completed
Affected source, both repair histories, release evidence, response, and regression conditions were reconciled.
9.3Sources and material
- Open WebUI GHSA-4pcg-253r-rf9w project advisoryhttps://github.com/open-webui/open-webui/security/advisories/GHSA-4pcg-253r-rf9w
- GitHub Security Lab GHSL-2026-002 technical advisoryhttps://securitylab.github.com/advisories/GHSL-2026-002_Open_WebUI/
- CVE Program record for CVE-2026-45350https://www.cve.org/CVERecord?id=CVE-2026-45350
- Open WebUI local-tool and tool-server access-control refactorhttps://github.com/open-webui/open-webui/commit/9b06fdc8fe1c933071610336be05f11e77e6c8eb
- Open WebUI generalized connection access repair used by the MCP pathhttps://github.com/open-webui/open-webui/commit/4737e1f11847d057859ec78892fa89e24cbcd83b
- Open WebUI v0.7.0 releasehttps://github.com/open-webui/open-webui/releases/tag/v0.7.0
- Open WebUI v0.8.6 releasehttps://github.com/open-webui/open-webui/releases/tag/v0.8.6
- Affected v0.6.43 chat completion routehttps://github.com/open-webui/open-webui/blob/v0.6.43/backend/open_webui/main.py
- Affected v0.6.43 completion middlewarehttps://github.com/open-webui/open-webui/blob/v0.6.43/backend/open_webui/utils/middleware.py
- Affected v0.6.43 tool resolverhttps://github.com/open-webui/open-webui/blob/v0.6.43/backend/open_webui/utils/tools.py
- Affected v0.6.43 tool record modelhttps://github.com/open-webui/open-webui/blob/v0.6.43/backend/open_webui/models/tools.py
- Fixed v0.8.6 completion middlewarehttps://github.com/open-webui/open-webui/blob/v0.8.6/backend/open_webui/utils/middleware.py
- Fixed v0.8.6 local tool resolverhttps://github.com/open-webui/open-webui/blob/v0.8.6/backend/open_webui/utils/tools.py
- Fixed v0.8.6 shared access-control helperhttps://github.com/open-webui/open-webui/blob/v0.8.6/backend/open_webui/utils/access_control/__init__.py
- Model Context Protocol tools specificationhttps://modelcontextprotocol.io/specification/2025-11-25/server/tools
- Model Context Protocol authorization specificationhttps://modelcontextprotocol.io/specification/2025-11-25/basic/authorization
- MITRE CWE-862 Missing Authorizationhttps://cwe.mitre.org/data/definitions/862.html
- OWASP API1:2023 Broken Object Level Authorizationhttps://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/