Skip to main content

Portainer CVE-2026-44883

HIGH
Use of GET Request Method With Sensitive Query Strings (CWE-598)
2026-05-14 https://github.com/portainer/portainer GHSA-jvp4-q659-95mj
7.7
CVSS 4.0 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
7.7 HIGH
CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Attack Vector
Network
Attack Complexity
High
Privileges Required
None
User Interaction
P
Scope
X

Lifecycle Timeline

7
Analysis Updated
May 28, 2026 - 22:31 vuln.today
v3 (cvss_changed)
Analysis Updated
May 28, 2026 - 22:31 vuln.today
v2 (cvss_changed)
Re-analysis Queued
May 28, 2026 - 22:22 vuln.today
cvss_changed
CVSS changed
May 28, 2026 - 22:22 NVD
7.7 (HIGH)
Source Code Evidence Fetched
May 14, 2026 - 17:32 vuln.today
Analysis Generated
May 14, 2026 - 17:32 vuln.today
CVE Published
May 14, 2026 - 16:33 nvd
HIGH

DescriptionGitHub Advisory

Summary

Portainer's authentication middleware accepts JWT bearer tokens passed as the ?token=<JWT> URL query parameter on any authenticated API endpoint, in addition to the standard Authorization: Bearer header. URLs are recorded in reverse-proxy access logs, browser history, and HTTP Referer headers on outbound navigation, so any JWT passed this way can be harvested by anyone with access to those logs or by an external site the user subsequently visits. A leaked token grants the full privileges of the user it was issued to, until the token expires (default 8 hours, configurable).

The ?token= parameter was used by Portainer's browser-based container attach, exec, and pod shell features, so any user with exec or attach rights on a container was exposed - not only administrators.

Severity

High

Attack complexity is High because exploitation depends on the attacker obtaining a leaked token from a log, referer, or shared URL. Once obtained, a leaked token grants the privileges of the user it was issued to; for administrator tokens this compromises confidentiality, integrity, and availability of Portainer itself and of every Docker/Kubernetes environment it manages - container exec and stack deployment make host-level compromise reachable, so subsequent-system impact is also High.

Affected Versions

Query-parameter token acceptance has existed since JWT authentication was introduced in Portainer.

Fixes are included in the following releases:

BranchFirst vulnerableFixed in
2.33.x (LTS)2.33.02.33.8
2.39.x (LTS)2.39.02.39.2
2.40.x (STS)all prior2.41.0

Portainer releases prior to 2.33.0 are end-of-life and will not receive a fix. Users on EOL versions should upgrade to a supported LTS branch.

Workarounds

Administrators who cannot immediately upgrade can reduce exposure by:

  • Stripping ?token= at the reverse proxy. A rewrite rule in nginx, Traefik, or equivalent that removes the token query parameter before the request reaches Portainer blocks the query-parameter auth path entirely. Container exec and interactive shells rely on the query-parameter token for WebSocket upgrade and will stop working until the patched release is deployed.
  • Auditing existing logs. Search reverse-proxy access logs and application logs for ?token= or &token= occurrences and treat any captured JWT as compromised. Resetting the affected user's password invalidates their sessions; reducing the JWT session timeout in Portainer settings shortens the exposure window for tokens already issued.
  • Administrator hygiene. Do not share Portainer URLs that contain ?token= in chat, email, or tickets, and avoid navigating to external sites from within the Portainer UI on unpatched instances - the Referer header will carry the token.

None of these replace the fix.

Affected Code

Pre-fix, extractBearerToken in api/http/security/bouncer.go read the JWT from the token query parameter before falling back to the Authorization header. The query.Del("token") call scrubs the parameter from r.URL.RawQuery on the way through Portainer, but by that point the original URL has already been recorded by any upstream reverse proxy, access logger, or browser.

go
func extractBearerToken(r *http.Request) (string, bool) {
    query := r.URL.Query()
    token := query.Get("token")
    if token != "" {
        query.Del("token")
        r.URL.RawQuery = query.Encode()
        return token, true
    }

    tokens, ok := r.Header[jwtTokenHeader]
    if !ok || len(tokens) == 0 {
        return "", false
    }
    // ...
}

The fix removes the query-parameter path entirely. Authenticated requests now carry the JWT via the Authorization header for API clients, or via the portainer_api_key HttpOnly cookie for the browser UI - cookies are sent automatically on same-origin WebSocket upgrade requests, so the browser-based container attach, exec, and pod shell features continue to work without exposing the token in the URL. The WebSocket handlers that previously documented ?token= as a required query parameter have been updated to match.

Impact

  • Token leakage to infrastructure. Intermediate systems that observe the request URL - reverse proxies, load balancers, access logs, WAFs, and corporate network monitoring - capture the full JWT in plaintext.
  • Token leakage via the browser. URLs containing ?token= are recorded in browser history and forwarded in the Referer header on any outbound navigation from the Portainer UI.
  • Account takeover. Anyone with access to a leaked JWT acts as the authenticated user for the remainder of the token's validity, without needing the password. If the leaked token belongs to an administrator, the attacker gains full API access including user management, container exec, and stack deployment.
  • Reach beyond Portainer. Container exec with an administrator JWT reaches the host filesystem of managed environments and can be used to execute commands on those hosts.

Timeline

  • 2026-03-06: Reported via GitHub Security Advisory by scanpwn.
  • 2026-04-14: Fix merged to develop.
  • 2026-04-29: 2.41.0 released.
  • 2026-05-07: 2.39.2-LTS and 2.33.8-LTS released.

Credit

  • scanpwn - identified and reported the query-parameter JWT acceptance and the resulting token-leakage vectors.

AnalysisAI

Token leakage in Portainer's authentication middleware allows JWT bearer tokens passed via the ?token=<JWT> URL query parameter to be harvested from reverse-proxy access logs, browser history, and HTTP Referer headers, enabling account takeover for the validity window of the token (default 8 hours). The flaw affected any user with container exec/attach rights - not just administrators - and a leaked admin token grants full control of Portainer and every managed Docker/Kubernetes environment. No public exploit identified at time of analysis, though the underlying behavior was present since JWT auth was introduced and the GitHub Security Advisory provides sufficient detail to weaponize.

Technical ContextAI

Portainer is a widely deployed container management UI for Docker, Swarm, Kubernetes, Nomad, and Podman environments. The root cause is CWE-598 (Use of GET Request Method With Sensitive Query Strings): the extractBearerToken function in api/http/security/bouncer.go read the JWT from r.URL.Query().Get("token") before falling back to the Authorization header. Although Portainer scrubbed the parameter via query.Del("token") after extraction, the original URL had already been observed by upstream reverse proxies, WAFs, load balancers, access loggers, and the browser itself. The ?token= mechanism existed because browser-based WebSocket upgrade requests for container attach, exec, and pod shell features cannot easily set custom Authorization headers; the fix replaces this with the portainer_api_key HttpOnly cookie, which browsers send automatically on same-origin WebSocket upgrades. Affected packages per the GHSA are go/github.com/portainer/portainer across the 2.33.x LTS, 2.39.x LTS, and 2.40.x STS branches.

RemediationAI

Vendor-released patches are available: upgrade to Portainer 2.33.8 (LTS), 2.39.2 (LTS), or 2.41.0 (STS) per the GitHub releases at https://github.com/portainer/portainer/releases/tag/2.33.8, /2.39.2, and /2.41.0. Users on end-of-life branches (<2.33.0) must migrate to a supported LTS line. If immediate upgrade is not possible, deploy a reverse-proxy rewrite rule in nginx, Traefik, or equivalent that strips the token query parameter before requests reach Portainer - note this will break browser-based container attach, exec, and pod shell features until the patched build is deployed, since those features rely on ?token= for WebSocket upgrade in unpatched versions. Audit existing reverse-proxy and application logs for occurrences of ?token= or &token= and treat any captured JWTs as compromised by resetting the affected users' passwords (which invalidates their existing sessions) and shortening the JWT session timeout in Portainer settings to reduce the window of exposure for already-issued tokens. Operationally, instruct administrators not to share URLs containing ?token= in chat, email, or tickets, and to avoid navigating to external sites from within the Portainer UI on unpatched instances because the Referer header will carry the token.

CVE-2025-1974 CRITICAL POC
9.8 Mar 25

A critical vulnerability in Kubernetes ingress-nginx controller allows unauthenticated attackers with pod network access

CVE-2026-45321 CRITICAL POC
9.6 May 12

Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio

CVE-2025-1098 HIGH POC
8.8 Mar 25

Kubernetes ingress-nginx contains a configuration injection vulnerability via the mirror-target and mirror-host Ingress

CVE-2025-24514 HIGH POC
8.8 Mar 25

A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-url` Ingres

CVE-2025-1097 HIGH POC
8.8 Mar 25

A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-tls-match-c

CVE-2020-8554 MEDIUM POC
6.3 Jan 21

Kubernetes API server in all versions allow an attacker who is able to create a ClusterIP service and set the spec.exter

CVE-2025-55190 CRITICAL POC
9.9 Sep 04

Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. Rated critical severity (CVSS 9.9), this vulne

CVE-2018-18843 CRITICAL POC
10.0 Dec 04

The Kubernetes integration in GitLab Enterprise Edition 11.x before 11.2.8, 11.3.x before 11.3.9, and 11.4.x before 11.4

CVE-2026-22039 CRITICAL POC
9.9 Jan 27

Kyverno Kubernetes policy engine prior to 1.x has a privilege escalation vulnerability (CVSS 9.9) allowing policy bypass

CVE-2024-42480 CRITICAL POC
9.9 Aug 12

Kamaji is the Hosted Control Plane Manager for Kubernetes. Rated critical severity (CVSS 9.9), this vulnerability is rem

CVE-2023-28110 CRITICAL POC
9.9 Mar 16

Jumpserver is a popular open source bastion host, and Koko is a Jumpserver component that is the Go version of coco, ref

CVE-2026-25996 CRITICAL POC
9.8 Feb 12

String filter bypass in Inspektor Gadget Kubernetes eBPF tooling before fix. Insufficient string escaping enables filter

Share

CVE-2026-44883 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy