KYAXRIS
ResearchProductsAboutContact
KYAXRIS

Red team research lab. We research how cloud and application infrastructure fails.

SiteResearchProductsAboutContact
PT Kyaxris Teknologi Nusantara2026
Unauthenticated ECS host bind-mount to Docker-host RCE / container escape in floci-io/floci | Kyaxris
Research

Unauthenticated ECS host bind-mount to Docker-host RCE / container escape in floci-io/floci

An unauthenticated ECS RegisterTaskDefinition plus RunTask bind-mounts the Docker host filesystem read-write into an attacker container and runs commands as root on the host.

SeverityCritical 10.0
CVSSAV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
AdvisoryGHSA-6f92-9q2p-fmpj
CWECWE-94, CWE-732
Affectedio.github.hectorvent:floci < 2.1.0 (patched 2.1.0)
CreditsMichael-JRead (Independent researcher), kangwijen (Kyaxris)
Published2026-09-18

Summary

Floci's ECS JSON-1.1 API is reachable unauthenticated on the default 0.0.0.0:4566 bind, and its RegisterTaskDefinition handler accepts a host volume host.sourcePath verbatim: no enabled-flag, no allowlist, no canonicalization, and no rejection of the Docker socket or sensitive paths.

When Floci is given the Docker socket (the standard configuration for ECS/Lambda/CodeBuild, where docker-compose.yml mounts /var/run/docker.sock by default) an unauthenticated attacker can call RegisterTaskDefinition with sourcePath="/" or /var/run/docker.sock and then RunTask to bind-mount the Docker host filesystem read-write into an attacker-controlled container and run an arbitrary command as root on the host. This is a full container escape and host takeover from a single unauthenticated network caller, and it works on the published native image.

Notably, Floci already gates the equivalent Lambda hot-reload host bind-mount with a default-off flag, an absolute-path check, and an allowlist, so host mounts are knowingly guarded elsewhere. The ECS path simply omits the same guards.

Severity

CVSS v3.1 base score 10.0, Critical: AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H.

The scope change (S:C) is what drives the score: the vulnerable component (the Floci container) is used to compromise a different security scope, the Docker host and every other container on it. The single environmental precondition, that Floci can reach the Docker socket, is the documented default-shipped configuration, so exploitation is the expected-deployment case rather than an edge case.

Root cause

An unauthenticated API entry point feeds an attacker-controlled host path straight into a Docker bind-mount with no guard:

  • The ECS JSON-1.1 dispatcher routes on X-Amz-Target with no signature verification and no IAM check. Signature validation and IAM enforcement are both off by default.
  • RegisterTaskDefinition stores each volume's host.sourcePath verbatim.
  • At launch, the container manager maps each mount point to its host source path and calls withBind / withReadOnlyBind directly, with no canonicalization, no allowlist, no enabled-flag, and no rejection of / or the Docker socket.
  • Real Docker mode is the default (ecs.mock = false), and the socket is mounted by the default docker-compose.yml.

Enabling the strongest available hardening does not stop it: the lone authorization filter is fail-open on a missing Authorization header, signature validation only guards S3 presigned URLs, and the TLS toggle does not force HTTPS. The only configurations that stop it both disable ECS entirely (ecs.mock=true or ecs.enabled=false), neither of which is an auth control.

Impact

  • Full Docker-host compromise from the network, unauthenticated: arbitrary read/write of every file on the host and command execution as root.
  • Container escape and lateral movement by mounting /var/run/docker.sock and driving the host's Docker daemon directly.
  • CI/CD and cloud blast radius, since the socket is exactly the configuration used when Floci backs ECS/Lambda/CodeBuild in pipelines and shared hosts.

Remediation

Gate ECS host volumes the way the Lambda hot-reload bind already is:

  • Add a default-off allowHostVolumes flag and reject task definitions that specify host.sourcePath unless explicitly enabled.
  • Canonicalize and validate the supplied path (resolve symlinks and ..) and require an absolute path.
  • Allowlist the resolved path against operator-provided prefixes.
  • Unconditionally deny sensitive targets: /, /var/run/docker.sock, the containerd socket, /proc, /sys, /etc, /root, and the host device tree.

Fixed in io.github.hectorvent:floci 2.1.0.

Disclosure

Reported privately via the floci-io/floci GitHub Security Advisory channel under coordinated disclosure. The proof-of-concept exploit is withheld from public disclosure until a fix ships.