All Advisories

mercure

Arbitrary Docker Container Configuration Leading to Host Compromise

mercure runs its processing modules as Docker containers. The module configuration includes a docker_arguments field whose JSON is passed straight to the Docker API as keyword arguments, with no validation. An administrator can therefore set container options such as privileged mode or a host-filesystem mount, launch a container through a matching rule, and escape to the Docker host. This crosses the line between the application administrator (any holder of a mercure web-interface admin session) and the infrastructure administrator (the IT team that owns the host).

Authored byVolker Schönefeld, Simon Weber2026-05-30
SeverityCriticalCVSS 9.1CVSS 3.1 VectorAV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:HCWECWE-250 (Execution with Unnecessary Privileges)ProductmercureAffected VersionsAll releases from 0.2.0-beta.1 through 0.4.0-beta.9.Fixed In0.4.1. The configuration editor now rejects dangerous docker_arguments and volume mounts, and processing containers default to cap_drop: ["ALL"] and network_mode: "none".CVEPendingGHSAPending

Description

mercure is an open-source DICOM orchestration platform; we appreciate the maintainers' prompt, constructive response to this report. mercure runs each processing module as a Docker container, which requires the processor to hold a Docker socket. That socket is an architectural given; the issue is what the web interface lets an administrator put through it.

The module configuration includes a docker_arguments field. Its value is stored verbatim, with no validation. The contact and comment fields are sanitized; the Docker-controlling fields are not:

app/webinterface/modules.py:58-81

async def save_module(form, name) -> None:
config.mercure.modules[name] = Module(
docker_tag=form.get("docker_tag", "").strip(),
additional_volumes=form.get("additional_volumes", ""),
environment=form.get("environment", ""),
docker_arguments=form.get("docker_arguments", ""),
settings=new_settings,
contact=strip_untrusted(form.get("contact", "")),
comment=strip_untrusted(form.get("comment", "")),
# ...
)
config.save_config()

View source →

At run time the stored JSON is decoded and splatted into the Docker SDK's containers.run() as keyword arguments:

app/process/process_series.py:268-278

arguments = decode_task_json(module.docker_arguments)
# ...
container = docker_client.containers.run(
docker_tag,
mounts=default_mounts,
volumes=additional_volumes,
environment=environment,
**runtime,
**set_command,
**arguments, # arbitrary kwargs from admin input
**user_info,
detach=True,
)

View source →

Any Docker run option can therefore be set. None of these are set by the existing code, so they pass cleanly through the keyword splat. A few that hand control of the host to the container:

Docker argumentEffect
privileged: trueFull host capabilities, all devices, no seccomp or AppArmor
pid_mode: "host"Container sees and can act on all host processes
network_mode: "host"Container shares the host network namespace
host bind mountMounts the host filesystem into the container

An administrator sets such arguments on a module, attaches it to a rule matching incoming series, and a matching DICOM series spawns the container. From a privileged or host-mounted container, reaching host root is a standard step we do not reproduce here. Chained with the missing-authorization privilege escalation or the default admin:router credentials, a lower-privileged or unauthenticated foothold reaches host root.

The proof of concept confirms a privileged container is spawned on the host daemon:

Proof-of-concept output

Privileged=true PidMode=host NetworkMode=bridge

Impact

  • A mercure application administrator (any user who holds an administrator session in the web interface) can escalate to root on the Docker host. A privileged or host-mounted container started through a matching rule gives full control of the host operating system.
  • Host access exposes the clinical network, credentials and keys for other services, and any patient data on shared storage.
  • Chained with the missing-authorization privilege escalation or the default admin:router credentials, a lesser or unauthenticated foothold reaches full host compromise.

Mitigation

Upgrade to mercure 0.4.1, which rejects dangerous docker_arguments and volume mounts and tightens container defaults (cap_drop: ["ALL"], network_mode: "none"). The general fix for this shape is to never pass user-supplied values straight into a container runtime: allowlist the Docker arguments an application administrator may set (resource limits, labels), restrict volume mounts to the configured data directories, and limit images to a trusted registry.

Defender's Checklist

  • Upgrade to 0.4.1 or later

    Deploy the patched release, which rejects dangerous Docker arguments and volume mounts by default.

  • Review module configurations

    Audit docker_arguments and additional_volumes in mercure.json for options such as privileged, pid_mode, host network, or host-path mounts.

  • Separate the roles

    Treat the mercure web administrator and the Docker host administrator as distinct trust levels; limit who can create or edit modules.

Severity Reasoning

AV:NModule and rule configuration is performed over the network through the web interface; the container launches on a network-delivered DICOM series.AC:LSetting the arguments and a matching rule is sufficient.PR:HModule configuration requires an administrator session.UI:NThe container launches automatically when a matching series arrives.S:CThe launched container escapes the mercure scope to control the Docker host and everything on it.C/I/A:HHost root yields full read, modification, and denial across the host and adjacent systems.

References

How We Can Help

Who We Are

The security researchers behind this advisory.

Dr. Simon Weber Profile

Dr. rer. nat. Simon Weber

Senior Pentester & MedSec Researcher

I evaluate your SaMD with the same industry-defining security insight I contributed to the BAK MV for the revision of the B3S standard.

  • PhD on Hospital Cybersecurity
  • Critical vulnerabilities found in hospital systems
  • Alumni of THB MedSec Research Group
  • gematik Security Hero
Volker Schönefeld Profile

Dipl.-Inf. Volker Schönefeld

Senior Application Security Expert

As a former CTO and developer turned pentester, I work alongside your team to uncover vulnerabilities and find solutions that fit your architecture.

  • 20+ years as CTO, 50M+ app downloads
  • Architected and secured large-scale IoT fleets
  • Certified Web Exploitation Specialist
  • gematik Security Hero

Looking for a Penetration Test?

Machine Spirits specializes in security assessments for medical devices and healthcare IT. From MDR penetration testing to C5 cloud compliance, we help MedTech companies meet regulatory requirements.