Skip to content

Commit f5b970a

Browse files
committed
security(idor): scope vmware/xhm migration list+detail to the caller's clusters
Final re-scan residual: /api/vmware/migrations and /api/xhm/migrations (list + detail) returned every tenant's migration tasks to any vm.migrate holder. Now filtered/gated so a caller only sees a migration touching a cluster they can reach (source or target); detail returns 404 otherwise. 277 tests.
1 parent b4a72a7 commit f5b970a

2 files changed

Lines changed: 20 additions & 2 deletions

File tree

pegaprox/api/vmware.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1126,9 +1126,16 @@ def start_vmware_migration(vmware_id, vm_id):
11261126

11271127
@bp.route('/api/vmware/migrations', methods=['GET'])
11281128
@require_auth(perms=['vmware.vm.migrate'])
1129+
def _migration_reachable(t):
1130+
# NS Jul 2026 (CodeAnt IDOR) — a caller may see a migration only if they can reach one of the
1131+
# clusters it touches (source or target). Tasks with no determinable cluster are shown.
1132+
cids = [c for c in (getattr(t, 'target_cluster', None), getattr(t, 'source_cluster', None)) if c]
1133+
return (not cids) or any(check_cluster_access(c)[0] for c in cids)
1134+
1135+
11291136
def list_vmware_migrations():
11301137
"""List all active and recent migrations"""
1131-
return jsonify([t.to_dict() for t in _vmware_migrations.values()])
1138+
return jsonify([t.to_dict() for t in _vmware_migrations.values() if _migration_reachable(t)])
11321139

11331140

11341141
@bp.route('/api/vmware/migrations/<mid>', methods=['GET'])
@@ -1137,6 +1144,8 @@ def get_vmware_migration_status(mid):
11371144
"""Get detailed status of a specific migration"""
11381145
if mid not in _vmware_migrations:
11391146
return jsonify({'error': 'Migration not found'}), 404
1147+
if not _migration_reachable(_vmware_migrations[mid]):
1148+
return jsonify({'error': 'Migration not found'}), 404
11401149
return jsonify(_vmware_migrations[mid].to_dict())
11411150

11421151

pegaprox/api/xhm.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,22 @@ def xhm_start():
193193

194194
@bp.route('/api/xhm/migrations', methods=['GET'])
195195
@require_auth(perms=['vm.migrate'])
196+
def _xhm_reachable(t):
197+
# NS Jul 2026 (CodeAnt IDOR) — show a migration only if the caller reaches one of its clusters.
198+
from pegaprox.api.helpers import check_cluster_access
199+
cids = [c for c in (getattr(t, 'target_cluster', None), getattr(t, 'source_cluster', None)) if c]
200+
return (not cids) or any(check_cluster_access(c)[0] for c in cids)
201+
202+
196203
def xhm_list():
197-
return jsonify([t.to_dict() for t in _xhm_migrations.values()])
204+
return jsonify([t.to_dict() for t in _xhm_migrations.values() if _xhm_reachable(t)])
198205

199206

200207
@bp.route('/api/xhm/migrations/<mid>', methods=['GET'])
201208
@require_auth(perms=['vm.migrate'])
202209
def xhm_detail(mid):
203210
if mid not in _xhm_migrations:
204211
return jsonify({'error': 'Migration not found'}), 404
212+
if not _xhm_reachable(_xhm_migrations[mid]):
213+
return jsonify({'error': 'Migration not found'}), 404
205214
return jsonify(_xhm_migrations[mid].to_dict())

0 commit comments

Comments
 (0)