All Advisories

mercure

Command Injection via Unquoted Target Fields in Connection Tests

When mercure tests a dispatch target's connection, it builds shell commands (ping, echoscu, sftp) by interpolating the target's configured fields into a string and running it through a shell. None of the fields are quoted or validated, across DICOM, DICOM+TLS, and SFTP targets, so an administrator can place shell metacharacters in any of them and run arbitrary commands as the mercure user. The safe pattern already exists in the codebase: the rsync handler builds commands as argument lists.

Authored byVolker Schönefeld, Simon Weber2026-05-30
SeverityHighCVSS 7.2CVSS 3.1 VectorAV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:HCWECWE-78 (OS Command Injection)ProductmercureAffected VersionsAll releases from 0.2.0-beta.1 through 0.4.0-beta.9.Fixed In0.4.1. The shell-injection class was removed across the dispatch code by routing commands through list-form execution (no shell) instead of string interpolation.CVEPendingGHSAPending

Description

mercure is an open-source DICOM orchestration platform; we appreciate the maintainers' prompt, constructive response to this report. When an administrator configures a dispatch target (a destination for processed studies), the web interface offers a "Test" button that checks connectivity.

Each target type's test builds shell commands from the target's fields and runs them through a shell. The DICOM test interpolates four fields into ping and echoscu without quoting:

app/dispatch/target_types/builtin.py:105-131

async def test_connection(self, target: DicomTarget, target_name: str):
target_ip = target.ip or ""
target_port = target.port or ""
target_aec = target.aet_target or "ANY-SCP"
target_aet = target.aet_source or "ECHOSCU"
if target_ip and target_port and not loopback_mode:
ping_result, *_ = await async_run(f"ping -w 1 -c 1 {target_ip}") # unquoted
# ...
cecho_result, *_ = await async_run(
f"echoscu -to 2 -aec {target_aec} -aet {target_aet} {target_ip} {target_port}"
)

View source →

DICOM+TLS adds the key, certificate, and CA paths, for seven injectable fields; SFTP interpolates the host, user, and folder. async_run() always uses a shell, so metacharacters in any field are interpreted:

FieldDICOMDICOM+TLSSFTP
ip / hostyesyesyes
portyesyes
aet_target / aet_sourceyesyes
tls_key / tls_cert / ca_certyes
user / folderyes

An administrator who sets any field to a value containing shell command-substitution syntax and clicks Test runs that command as the mercure user; the test still returns success, so there is no visible indication. The test endpoint itself requires only an authenticated session, so once a malicious target exists, any logged-in user can trigger it. We are not publishing a working payload. The SFTP password is a separate instance of the same pattern, covered in the SFTP password injection advisory.

The safe pattern is already present: the rsync handler builds commands as argument lists and runs them with async_run_exec() (no shell).

app/dispatch/target_types/rsync.py:139

result, stdout, stderr = await async_run_exec(*c) # create_subprocess_exec, no shell

View source →

Command execution as the mercure user is confirmed by the output of an injected id:

Proof-of-concept output

uid=1000(mercure) gid=1000(mercure) groups=1000(mercure)

Impact

  • An administrator can run arbitrary OS commands as the mercure user in the UI container by placing shell metacharacters in any target field and testing the target. This affects every field across DICOM, DICOM+TLS, and SFTP targets.
  • The test endpoint requires only an authenticated session, so once a malicious target is stored, any logged-in user can trigger the injection.
  • The UI container reaches the shared configuration volume, Redis, and the Docker network, so command execution there is a foothold into the rest of the deployment.

Mitigation

Upgrade to mercure 0.4.1, which routes dispatch commands through list-form execution instead of building shell strings. In general, build external commands as argument vectors with create_subprocess_exec (the codebase's async_run_exec), never interpolate untrusted values into a shell string, and validate target fields (AE titles, IPs, ports) against their expected formats.

Defender's Checklist

  • Upgrade to 0.4.1 or later

    Deploy the patched release, which removes shell execution from the dispatch handlers.

  • Review configured targets

    Audit target fields in mercure.json for shell metacharacters in IP, AE title, certificate path, host, user, or folder values.

  • Restrict administrator access

    Limit administrator credentials and confirm the default admin password has been changed.

Severity Reasoning

AV:NTargets are configured and tested over the network through the web interface.AC:LSetting a field and triggering the test is sufficient.PR:HCreating or editing a target requires an administrator session.UI:NNo user interaction beyond the attacker's own request.S:UExecution stays within the UI service account's scope.C/I/A:HCommand execution as the mercure user exposes and can modify the data and configuration it reaches and can disrupt the service.

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.