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).
docker_arguments and volume mounts, and processing containers default to cap_drop: ["ALL"] and network_mode: "none".CVEPendingGHSAPendingDescription
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()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,)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 argument | Effect |
|---|---|
privileged: true | Full 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 mount | Mounts 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=bridgeImpact
- 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:routercredentials, 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_argumentsandadditional_volumesinmercure.jsonfor options such asprivileged,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
References
How We Can Help
Who We Are
The security researchers behind this advisory.

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

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.
