Red-team operations
Red-team operations on a running lab (Redteam API)
Red-team actions on a running lab — inspecting attacker sessions, running custom commands, playing Atomic Red Team tests, uploading files — are served by the Redteam API, a service that runs inside each lab. It is a different API from the Scenario API; its full reference is here: Redteam API reference.
Runtime address (per lab)
Unlike the Scenario API, the Redteam API is reached per lab through the platform gateway proxy:
https://app.<your-domain>/proxy/<lab-id>/api/redteam<lab-id> is the id returned when you launched the lab (POST /scenario/run_lab) or listed labs (GET /runner/ on the Scenario API). This is exactly the URL the mantis CLI builds in set_current_lab().
Authentication is the same OIDC Bearer token as the rest of the platform (the proxy authenticates the request) — see the Authentication guide.
export RT="https://app.mantis-platform.io/proxy/$LAB_ID/api/redteam"
export TOKEN="<your access token>"Asynchronous execution
Commands are queued, not run synchronously: POST /command (and POST /atomic) return an identifier immediately; you then pollGET /command/{id} until its output is set. All commands run against an existing attack session (a foothold), identified by its identifier.
1. List attack sessions
Every red-team action targets an attack session. List them first:
curl "$RT/attack_sessions" -H "Authorization: Bearer $TOKEN"import requests
RT = "https://app.mantis-platform.io/proxy/" + LAB_ID + "/api/redteam"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
sessions = requests.get(f"{RT}/attack_sessions", headers=HEADERS).json()["attack_sessions"]
for s in sessions:
print(s["identifier"], s.get("type"), s.get("username"))
session_id = sessions[0]["identifier"]2. Run a custom command
POST /command queues a command on a session and returns an idResultCommand; poll GET /command/{id} for status / output.
# 1) queue
curl -X POST "$RT/command" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"command": "whoami", "identifier": "'"$SESSION_ID"'", "title": "CUSTOM EXECUTION"}'
# -> {"idResultCommand": 42}
# 2) poll
curl "$RT/command/42" -H "Authorization: Bearer $TOKEN"import time
def run_command(command, session_id, timeout=60):
r = requests.post(
f"{RT}/command",
json={"command": command, "identifier": session_id, "title": "CUSTOM EXECUTION"},
headers=HEADERS,
)
r.raise_for_status()
cid = r.json()["idResultCommand"]
for _ in range(timeout):
result = requests.get(f"{RT}/command/{cid}", headers=HEADERS).json()
if result.get("output"):
return result["output"]
time.sleep(1)
raise TimeoutError(f"command {cid} timed out")
print(run_command("whoami", session_id))3. Play an Atomic Red Team test
POST /atomic uploads an Atomic Red Team (ATR) YAML file and runs its tests against a session, returning a list of command ids to poll individually.
curl -X POST "$RT/atomic?attack_session_identifier=$SESSION_ID" \
-H "Authorization: Bearer $TOKEN" \
-F "upload_file=@T1053.003.yaml"
# -> [101, 102] (poll each with GET /command/{id})with open("T1053.003.yaml", "rb") as f:
r = requests.post(
f"{RT}/atomic",
params={"attack_session_identifier": session_id},
files={"upload_file": f},
headers=HEADERS,
)
r.raise_for_status()
for cid in r.json():
while True:
result = requests.get(f"{RT}/command/{cid}", headers=HEADERS).json()
if result.get("output"):
print(cid, result["status"], result["output"])
break
time.sleep(1)4. Upload a file to a target
POST /upload pushes a local file to the target of a session (e.g. a payload).
curl -X POST "$RT/upload?identifier=$SESSION_ID" \
-H "Authorization: Bearer $TOKEN" \
-F "upload_file=@./payload.exe"with open("payload.exe", "rb") as f:
requests.post(
f"{RT}/upload",
params={"identifier": session_id},
files={"upload_file": f},
headers=HEADERS,
).raise_for_status()See also
- Full endpoint reference: Redteam API.
- Reading results on the Scenario API side: Running-lab operations (attack report and security alerts).

