# [CRIT] [GHSA / CRITICAL] CVE-2026-44849: Portainer has an endpoint security bypass via Swarm service create/update

**Source:** GitHub Security Advisories
**Published:** 2026-05-14
**Article:** https://github.com/advisories/GHSA-5fxq-qcf3-244w

## Threat Profile

Portainer has an endpoint security bypass via Swarm service create/update

## Summary

Portainer enforces seven `EndpointSecuritySettings` restrictions that administrators configure to restrict the container configurations non-admin users can launch: **privileged mode**, **host PID namespace**, **device mapping**, **capabilities**, **sysctls**, **security-opt (Seccomp / AppArmor)**, and **bind mounts**.

The vulnerability is exposed when a non-admin Portainer user (Standard User role, or any rol…

## Indicators of Compromise (high-fidelity only)

- **CVE:** `CVE-2026-44849`

## MITRE ATT&CK Techniques

- **T1190** — Exploit Public-Facing Application
- **T1543.003** — Persistence (article-specific)
- **T1078.003** — Valid Accounts: Local Accounts
- **T1611** — Escape to Host
- **T1610** — Deploy Container
- **T1068** — Exploitation for Privilege Escalation
- **T1059.004** — Command and Scripting Interpreter: Unix Shell
- **T1613** — Container and Resource Discovery
- **T1525** — Implant Internal Image

## Kill chain phases observed

_(none detected from narrative keywords)_

## Recommended hunts

### Portainer Swarm service create/update API access (CVE-2026-44849 exploitation path)

`UC_297_2` · phase: **exploit** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime values(Web.http_method) as http_method values(Web.url) as url values(Web.src) as src values(Web.user) as user from datamodel=Web where Web.url="*/services/create*" OR Web.url="*/services/*/update*" OR Web.url="*/volumes/create*" Web.http_method="POST" by Web.dest Web.user | `drop_dm_object_name(Web)` | rename dest as portainer_host | where isnotnull(portainer_host)
```

**Defender KQL:**
```kql
DeviceNetworkEvents
| where Timestamp > ago(7d)
| where isnotempty(RemoteUrl)
| where RemoteUrl has_any ("/services/create", "/volumes/create")
   or RemoteUrl matches regex @"/services/[^/]+/update"
| where RemotePort in (9000, 9443, 8000, 443)
| summarize FirstSeen = min(Timestamp), LastSeen = max(Timestamp), Hits = count(), AnyCmd = any(InitiatingProcessCommandLine)
          by DeviceName, InitiatingProcessFileName, RemoteIP, RemoteUrl
| order by LastSeen desc
```

### Portainer Swarm service spec with elevated Linux capabilities or unconfined Seccomp

`UC_297_3` · phase: **exploit** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime values(Processes.process) as cmdline values(Processes.user) as user from datamodel=Endpoint.Processes where (Processes.process_name="dockerd" OR Processes.process_name="containerd-shim" OR Processes.process_name="runc" OR Processes.parent_process_name="dockerd") AND (Processes.process="*cap_sys_admin*" OR Processes.process="*CAP_SYS_ADMIN*" OR Processes.process="*cap_net_admin*" OR Processes.process="*cap_sys_ptrace*" OR Processes.process="*--privileged*" OR Processes.process="*seccomp=unconfined*" OR Processes.process="*apparmor=unconfined*") by Processes.dest Processes.user Processes.process_name | `drop_dm_object_name(Processes)`
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("dockerd", "containerd", "containerd-shim", "containerd-shim-runc-v2")
   or FileName in~ ("runc", "crun", "containerd-shim", "containerd-shim-runc-v2")
| where ProcessCommandLine has_any ("CAP_SYS_ADMIN", "CAP_NET_ADMIN", "CAP_SYS_PTRACE", "cap_sys_admin", "cap_net_admin", "cap_sys_ptrace", "\"ALL\"", "seccomp=unconfined", "apparmor=unconfined", "AppArmorProfile=unconfined", "\"Mode\":\"unconfined\"")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          InitiatingProcessParentFileName
| order by Timestamp desc
```

### Container escape via chroot/nsenter against mounted host filesystem

`UC_297_4` · phase: **actions** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime values(Processes.process) as cmdline values(Processes.parent_process) as parent_cmdline values(Processes.user) as user from datamodel=Endpoint.Processes where (Processes.process_name="chroot" OR Processes.process_name="nsenter") AND (Processes.process="*/host*" OR Processes.process="*/proc/1/ns*" OR Processes.process="*/proc/1/root*" OR Processes.process="*--target 1*" OR Processes.process="*--mount=/proc/1*") by Processes.dest Processes.user Processes.process_name | `drop_dm_object_name(Processes)`
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("chroot", "nsenter")
| where ProcessCommandLine has_any ("/host", "/proc/1/ns", "/proc/1/root", "--target 1", "--target=1", "-t 1")
| where InitiatingProcessFileName !in~ ("init", "systemd", "snapd", "snap-confine", "docker-init", "tini")
| where AccountName != "root" or InitiatingProcessParentFileName in~ ("containerd-shim", "containerd-shim-runc-v2", "runc", "crun", "dockerd")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          InitiatingProcessParentFileName, InitiatingProcessParentCreationTime
| order by Timestamp desc
```

### Container start with docker.sock or sensitive host-path bind mount

`UC_297_5` · phase: **exploit** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime values(Processes.process) as cmdline values(Processes.user) as user from datamodel=Endpoint.Processes where (Processes.process_name="runc" OR Processes.process_name="crun" OR Processes.process_name="containerd-shim" OR Processes.process_name="containerd-shim-runc-v2" OR Processes.process_name="dockerd") AND (Processes.process="*/var/run/docker.sock*" OR Processes.process="*source=/ *" OR Processes.process="*source=/,*" OR Processes.process="*-v /:*" OR Processes.process="*/root/.ssh*" OR Processes.process="*/data/portainer*") by Processes.dest Processes.user Processes.process_name | `drop_dm_object_name(Processes)`
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("dockerd", "containerd", "containerd-shim", "containerd-shim-runc-v2")
   or FileName in~ ("runc", "crun", "containerd-shim", "containerd-shim-runc-v2")
| where ProcessCommandLine has_any ("/var/run/docker.sock", "docker.sock", "-v /:", "--volume=/:", "source=/ ", "source=/,", "source=/var/run/docker.sock", "/root/.ssh", "/data/portainer", "/host/etc", "\"Source\":\"/\"")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          InitiatingProcessParentFileName
| order by Timestamp desc
```

### Docker local-driver volume created with type=none and o=bind (CVE-2026-44849 volume variant)

`UC_297_6` · phase: **exploit** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime values(Processes.process) as cmdline values(Processes.user) as user from datamodel=Endpoint.Processes where (Processes.process_name="dockerd" OR Processes.process_name="docker") AND ((Processes.process="*type=none*" AND Processes.process="*o=bind*" AND Processes.process="*device=*") OR (Processes.process="*volume create*" AND Processes.process="*--driver local*" AND Processes.process="*-o type=none*") OR (Processes.process="*VolumeOptions*" AND Processes.process="*DriverConfig*")) by Processes.dest Processes.user Processes.process_name | `drop_dm_object_name(Processes)`
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("dockerd", "docker", "containerd") or FileName in~ ("docker", "dockerd")
| where (ProcessCommandLine has "type=none" and ProcessCommandLine has "o=bind" and ProcessCommandLine has "device=")
     or (ProcessCommandLine has "volume create" and ProcessCommandLine has "--driver local" and ProcessCommandLine has_any ("-o type=none", "--opt type=none"))
     or (ProcessCommandLine has "VolumeOptions" and ProcessCommandLine has "DriverConfig")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine
| order by Timestamp desc
```

### Article-specific behavioural hunt — [GHSA / CRITICAL] CVE-2026-44849: Portainer has an endpoint security bypass via

`UC_297_1` · phase: **install** · confidence: **High**

**Splunk SPL (CIM):**
```spl
``` Article-specific bespoke detection — [GHSA / CRITICAL] CVE-2026-44849: Portainer has an endpoint security bypass via ```
| tstats `summariesonly` count
    from datamodel=Endpoint.Filesystem
    where Filesystem.action IN ("created","modified")
      AND (Filesystem.file_path="*/var/run/docker.sock*")
    by Filesystem.dest, Filesystem.user, Filesystem.process_name,
       Filesystem.file_path, Filesystem.file_name
| `drop_dm_object_name(Filesystem)`
```

**Defender KQL:**
```kql
// Article-specific bespoke detection — [GHSA / CRITICAL] CVE-2026-44849: Portainer has an endpoint security bypass via
// Hunts the actual binaries / paths / commandline fragments named
// in the article instead of a generic technique-class template.

// File-creation events for the named binaries / paths
DeviceFileEvents
| where Timestamp > ago(30d)
| where ActionType in ("FileCreated","FileModified")
| where (FolderPath has_any ("/var/run/docker.sock"))
| project Timestamp, DeviceName, AccountName, FolderPath,
          FileName, ActionType, InitiatingProcessFileName,
          InitiatingProcessCommandLine
| order by Timestamp desc
```

### IOC-driven hunts (use shared templates)

These are standard IOC-substitution hunts — the canonical SPL and KQL live once in [`_TEMPLATES.md`](../_TEMPLATES.md), so we don't repeat the same boilerplate on every CVE / hash / network-IOC briefing.

- **Asset exposure — vulnerability matches article CVE(s)** ([template](../_TEMPLATES.md#asset-exposure)) — phase: **recon**, confidence: **High**
  - CVE(s): `CVE-2026-44849`


## Why this matters

Severity classified as **CRIT** based on: CVE present, 7 use case(s) fired, 9 technique(s) inferred. Read the full article for actor attribution, tooling details, and any defanged IOCs in the body that aren't visible in the RSS summary.
