The vulnerability exists in the Docker API proxy layer of Portainer, specifically within the ProxyDockerRequest function located in api/http/proxy/factory/docker/transport.go. This function is intended to enforce Role-Based Access Control (RBAC) by routing requests through authorization handlers based on the URL prefix.
The vulnerability arises because the prefixProxyFuncMap, which maps URL prefixes to their respective handlers, did not include an entry for /plugins. Consequently, any API requests targeting Docker plugin management endpoints (e.g., /plugins/pull, /plugins/{name}/enable) would not match any entry in the map.
In the vulnerable code, this lack of a match caused the function to fall through to a final transport.executeDockerRequest(request) call. This call directly forwards the request to the underlying Docker daemon without performing any of Portainer's authorization checks. This allowed any authenticated user with access to a Docker endpoint, regardless of their role, to execute privileged plugin operations.
The patch for this vulnerability, found in commit 6024a978924c3aa99cbbbc9ffdfe94c3fd56cd10, addresses this by introducing a new check. It adds a function isAdminOnlyRoute that uses regular expressions to identify requests to sensitive plugin endpoints. Before falling through to the unauthorized executeDockerRequest, the ProxyDockerRequest function now checks if the request is an admin-only route and, if so, passes it to transport.administratorOperation(request), which correctly enforces administrator-only permissions. The primary vulnerable function is Transport.ProxyDockerRequest because it contains the flawed logic that fails to enforce authorization.