Skip to content

Add Portainer authenticated Docker API root RCE - #21745

Open
Gill-Singh-A wants to merge 10 commits into
rapid7:masterfrom
Gill-Singh-A:portainer-authenticated-docker-rce
Open

Add Portainer authenticated Docker API root RCE#21745
Gill-Singh-A wants to merge 10 commits into
rapid7:masterfrom
Gill-Singh-A:portainer-authenticated-docker-rce

Conversation

@Gill-Singh-A

@Gill-Singh-A Gill-Singh-A commented Aug 3, 2026

Copy link
Copy Markdown

Description

New module: exploits/linux/http/portainer_authenticated_docker_rce.

Portainer proxies the full Docker Engine API to authenticated users who have access to a
managed Docker environment. Because the Docker daemon runs as root, an authenticated user can
create a privileged container that bind-mounts the host root filesystem (/:/host) and
chroots into it, gaining code execution as root on the Docker host — not merely inside a
container.

The module authenticates to Portainer (POST /api/auth), selects a Docker environment, ensures
a payload image is present (pulling alpine:latest only if missing), creates a privileged
host-mounted container that drops and runs a native Metasploit payload under chroot /host, and
opens a session as host root. The payload is launched via the host's init (systemd) so it
survives removal of the throwaway container, which is stopped and force-removed during cleanup.
The default target is native Linux Meterpreter (x64/x86); a secondary cmd/unix command target
is included.

This is an abuse of intended functionality combined with a common misconfiguration (a
network-reachable Portainer instance protected only by weak or shared credentials), so it
references the original research rather than a CVE. Original research and proof of concept by
Aman Singh Gill (Gill-Singh-A):

Related Issue: N/A

Breaking Changes

None

Reviewer Notes

Post-authentication only — no brute forcing is bundled. The host-side launcher is deliberately
defensive so it works across old and new hosts/Portainer versions: it decodes the payload with
the container image's own busybox base64, feeds a POSIX launcher to the host /bin/sh over
stdin via chroot (no quoting pitfalls across dash/bash/busybox), probes for an exec-capable
directory (handles a noexec /tmp), relabels for SELinux enforcing hosts (chcon -t bin_t,
best-effort), and launches via systemd-run (falling back to plain systemd-run on old systemd
without --collect, then to setsid). Container create accepts both HTTP 200 (older Portainer)
and 201.

Verification Steps

    • Deploy Portainer against the host Docker socket:
      docker run -d -p 9443:9443 -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:lts,
      then create the initial admin account in the web UI.
    • Start msfconsole and do: use exploit/linux/http/portainer_authenticated_docker_rce
    • set RHOSTS <target>; set USERNAME <user>; set PASSWORD <pass>; set LHOST <you>
      (for a plain-HTTP instance: set RPORT 9000 and set SSL false)
    • check → it reports the Portainer version and that the credentials are valid.
    • run → a Meterpreter session opens as root on the Docker host.
    • Confirm host root: getuid returns root, sysinfo shows the host, and in a shell
      cat /proc/1/comm returns systemd (host PID 1, not a container).
    • Confirm the temporary container was removed automatically ([+] Removed container ...).

Test Evidence

Verified as host root against multiple Portainer versions and Linux distributions
(IPs/credentials sanitized).

Portainer 2.39.5 on Fedora 44 (native Meterpreter):

[+] The target appears to be vulnerable. Portainer 2.39.5; credentials are valid and a Docker environment is reachable
[+] Authenticated to Portainer, received a JWT
[*] Selected Docker environment 'local' (id 3)
[*] Delivering native payload (ELF dropper) to the host
[*] Created container 88f2e8a73fca, starting it to launch the payload on the host
[*] Meterpreter session 1 opened
[+] Removed container 88f2e8a73fca
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : fedora
OS           : Fedora 44 (Linux 7.1.5-200.fc44.x86_64)
Architecture : x64
Meterpreter  : x64/linux

Portainer 2.16.2 on CentOS 7.9 (auto image pull + CLEANUP_IMAGE):

[+] The target appears to be vulnerable. Portainer 2.16.2; credentials are valid and a Docker environment is reachable
[*] Image 'alpine:latest' not present, attempting to pull it (this may take a while)
[*] Created container 010bd1084b98, starting it to launch the payload on the host
[*] Meterpreter session 1 opened
[+] Removed container 010bd1084b98
[+] Removed image 'alpine:latest' (pulled by this module)
meterpreter > sysinfo
OS           : CentOS 7.9.2009 (Linux 3.10.0-1160.88.1.el7.centos.plus.x86_64)

Also verified: Portainer 2.0.1 on Ubuntu 18.04.4 (cmd/unix target, host root), the cmd/unix
target on Fedora, RHOSTS list/file iteration, and check failure paths (rejected credentials,
non-Portainer service). msftidy, rubocop, and msftidy_docs are all clean.

Environment

Field Details
Operating System Fedora 44, CentOS 7.9.2009, Ubuntu 18.04.4
Target Software/Hardware Portainer CE 2.0.1 / 2.16.2 / 2.39.5 (Docker Engine 20.10–29.x)
Docker Image / Vagrant Setup portainer/portainer-ce:lts bound to /var/run/docker.sock

AI Usage Disclosure

AI-assisted (Claude Code) for code generation, documentation drafting, and test orchestration.
All behavior was verified by hand against live Portainer instances on three Linux distributions
before submission.

Pre-Submission Checklist

  • Included a corresponding documentation markdown file in documentation/modules (new modules only)
  • No sensitive information (IP addresses, credentials, API keys, hashes) in code or documentation
  • Tested on the target environment specified in the Environment section above
  • Included RSpec tests for library changes (encouraged for lib/ changes)
  • Read the CONTRIBUTING.md and module acceptance guidelines

Gill-Singh-A and others added 2 commits August 3, 2026 21:18
Authenticated Portainer users can drive the Docker Engine API to create a
privileged host-mounted container and chroot to root on the Docker host.
Adds the exploit module and documentation.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Metasploit exploit module and accompanying documentation to gain host root RCE by abusing Portainer’s authenticated proxy access to the Docker Engine API (creating a privileged, host-mounted container and executing a payload via chroot /host).

Changes:

  • Introduces exploit/linux/http/portainer_authenticated_docker_rce, including Portainer auth (JWT), endpoint selection, optional image pull, privileged container creation, host payload drop/launch, and container/image cleanup.
  • Adds full module documentation with setup, options, verification steps, scenarios, and limitations.

Impact Analysis: isolated change; no meaningful downstream impact identified from diff.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
modules/exploits/linux/http/portainer_authenticated_docker_rce.rb New exploit module implementing authenticated Portainer→Docker API host-root payload deployment and cleanup.
documentation/modules/exploit/linux/http/portainer_authenticated_docker_rce.md New documentation describing prerequisites, usage, options, and example runs.

Comment thread modules/exploits/linux/http/portainer_authenticated_docker_rce.rb
Comment thread modules/exploits/linux/http/portainer_authenticated_docker_rce.rb
Comment thread modules/exploits/linux/http/portainer_authenticated_docker_rce.rb Outdated
Gill-Singh-A and others added 2 commits August 6, 2026 23:52
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CmdStager API unused, only generate_payload_exe needed
Comment thread modules/exploits/linux/http/portainer_authenticated_docker_rce.rb
Comment thread modules/exploits/linux/http/portainer_authenticated_docker_rce.rb Outdated
Comment thread modules/exploits/linux/http/portainer_authenticated_docker_rce.rb Outdated
Comment thread modules/exploits/linux/http/portainer_authenticated_docker_rce.rb Outdated
Comment thread modules/exploits/linux/http/portainer_authenticated_docker_rce.rb Outdated
Comment thread modules/exploits/linux/http/portainer_authenticated_docker_rce.rb Outdated
Comment thread modules/exploits/linux/http/portainer_authenticated_docker_rce.rb Outdated
Gill-Singh-A and others added 6 commits August 7, 2026 16:16
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
Co-authored-by: msutovsky-r7 <martin_sutovsky@rapid7.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

3 participants