T05 · Unauthorized Access and Privilege Escalation
- Location
oasis/server.py:122- Finding
Administrator Token Exfiltration Through an Attacker-Controlled Callback
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
TeamClaw is a disclosed multi-agent service, but it grants broad local execution, credential, session, and network authority with several under-scoped security controls.
Install only if you intend to run a broad local agent platform and can isolate it. Keep it on loopback unless you add strong authentication, avoid the public tunnel on untrusted networks, do not expose OASIS directly, rotate any configured OpenClaw/API/internal tokens after testing, and treat the command/code execution tools as full local code execution rather than a sandbox.
oasis/server.py:122Administrator Token Exfiltration Through an Attacker-Controlled Callback
oasis/server.py:659Unauthenticated OASIS Administration and OpenClaw API-Key Disclosure
src/mcp_commander.py:194Command Sandbox Permits Unrestricted Native Code Execution
scripts/setup_env.sh:13Mutable Remote Scripts and Binaries Are Downloaded and Executed Without Integrity Verification
oasis/server.py:522Unauthenticated Path Traversal in Workflow and Discussion Persistence
src/agent.py:449Persistent User Profile Is Injected Into the System Prompt Without Trust Separation
config/requirements.txt:1All Python Dependencies Are Installed Without Version or Hash Pinning
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
# 直接透传请求体和 Authorization header 到后端
auth_header = request.headers.get("Authorization", "")
try:
r = requests.post(
LOCAL_OPENAI_COMPLETIONS_URL,
json=request.get_json(silent=True),
headers={
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
def proxy_openai_models():
"""透传 /v1/models"""
try:
r = requests.get(f"http://127.0.0.1:{PORT_AGENT}/v1/models", timeout=10)
return Response(r.content, status=r.status_code, content_type=r.headers.get("content-type", "application/json"))
except Exception as e:
return jsonify({"error": str(e)}), 500
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
password = request.json.get("password", "")
try:
r = requests.post(LOCAL_LOGIN_URL, json={"user_id": user_id, "password": password}, timeout=10)
if r.status_code == 200:
# 登录成功,在 Flask session 中记录
session["user_id"] = user_id
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
}
try:
r = requests.post(
LOCAL_OPENAI_COMPLETIONS_URL,
json=openai_payload,
headers={"Authorization": f"Bearer {user_id}:{password}"},
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
}
try:
r = requests.post(
LOCAL_OPENAI_COMPLETIONS_URL,
json=openai_payload,
headers={"Authorization": f"Bearer {user_id}:{password}"},
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return jsonify({"error": "未登录"}), 401
session_id = request.json.get("session_id", "default") if request.is_json else "default"
try:
r = requests.post(LOCAL_AGENT_CANCEL_URL, json={"user_id": user_id, "password": password, "session_id": session_id}, timeout=5)
return jsonify(r.json())
except Exception as e:
return jsonify({"error": str(e)}), 500
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
payload = {"user_id": user_id, "password": password, "text": text}
if voice:
payload["voice"] = voice
r = requests.post(LOCAL_TTS_URL, json=payload, timeout=60)
if r.status_code != 200:
return jsonify({"error": f"TTS 服务错误: {r.status_code}"}), r.status_code
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
def proxy_tools():
"""代理获取工具列表请求到后端 Agent"""
try:
r = requests.get(LOCAL_TOOLS_URL, headers={"X-Internal-Token": INTERNAL_TOKEN}, timeout=10)
return jsonify(r.json())
except Exception as e:
return jsonify({"error": str(e), "tools": []}), 500
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if not user_id or not password:
return jsonify({"error": "未登录"}), 401
try:
r = requests.post(LOCAL_SESSIONS_URL, json={"user_id": user_id, "password": password}, timeout=15)
return jsonify(r.json()), r.status_code
except Exception as e:
return jsonify({"error": str(e)}), 500
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if not user_id or not password:
return jsonify({"error": "未登录"}), 401
try:
r = requests.post(
f"http://127.0.0.1:{PORT_AGENT}/sessions_status",
json={"user_id": user_id, "password": password},
timeout=5,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"""Proxy to fetch OpenClaw session list from OASIS server."""
filter_kw = request.args.get("filter", "")
try:
r = requests.get(
f"{OASIS_BASE_URL}/sessions/openclaw",
params={"filter": filter_kw},
timeout=10,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return jsonify({"error": "未登录"}), 401
sid = request.json.get("session_id", "")
try:
r = requests.post(LOCAL_SESSION_HISTORY_URL, json={
"user_id": user_id, "password": password, "session_id": sid
}, timeout=15)
return jsonify(r.json()), r.status_code
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return jsonify({"has_new_messages": False}), 200
sid = request.json.get("session_id", "") if request.is_json else ""
try:
r = requests.post(LOCAL_SESSION_STATUS_URL, json={
"user_id": user_id, "password": password, "session_id": sid
}, timeout=5)
return jsonify(r.json()), r.status_code
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return jsonify({"error": "未登录"}), 401
sid = request.json.get("session_id", "") if request.is_json else ""
try:
r = requests.post(LOCAL_DELETE_SESSION_URL, json={
"user_id": user_id, "password": password, "session_id": sid
}, timeout=15)
return jsonify(r.json()), r.status_code
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if not uid:
return jsonify([]), 200
try:
r = requests.get(f"http://127.0.0.1:{PORT_AGENT}/groups", headers=headers, timeout=10)
return jsonify(r.json()), r.status_code
except Exception as e:
return jsonify({"error": str(e)}), 500
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return jsonify({"error": "未登录"}), 401
try:
headers["Content-Type"] = "application/json"
r = requests.post(f"http://127.0.0.1:{PORT_AGENT}/groups", json=request.get_json(silent=True), headers=headers, timeout=10)
return jsonify(r.json()), r.status_code
except Exception as e:
return jsonify({"error": str(e)}), 500
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if not uid:
return jsonify({"error": "未登录"}), 401
try:
r = requests.get(f"http://127.0.0.1:{PORT_AGENT}/groups/{group_id}", headers=headers, timeout=10)
return jsonify(r.json()), r.status_code
except Exception as e:
return jsonify({"error": str(e)}), 500
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return jsonify({"error": "未登录"}), 401
try:
headers["Content-Type"] = "application/json"
r = requests.put(f"http://127.0.0.1:{PORT_AGENT}/groups/{group_id}", json=request.get_json(silent=True), headers=headers, timeout=10)
return jsonify(r.json()), r.status_code
except Exception as e:
return jsonify({"error": str(e)}), 500
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return jsonify({"messages": []}), 200
try:
after_id = request.args.get("after_id", "0")
r = requests.get(
f"http://127.0.0.1:{PORT_AGENT}/groups/{group_id}/messages",
params={"after_id": after_id},
headers=headers, timeout=10,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return jsonify({"error": "未登录"}), 401
try:
headers["Content-Type"] = "application/json"
r = requests.post(
f"http://127.0.0.1:{PORT_AGENT}/groups/{group_id}/messages",
json=request.get_json(silent=True),
headers=headers, timeout=10,
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if not uid:
return jsonify({"error": "未登录"}), 401
try:
r = requests.post(
f"http://127.0.0.1:{PORT_AGENT}/groups/{group_id}/mute",
headers=headers, timeout=10,
)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if not uid:
return jsonify({"error": "未登录"}), 401
try:
r = requests.post(
f"http://127.0.0.1:{PORT_AGENT}/groups/{group_id}/unmute",
headers=headers, timeout=10,
)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if not uid:
return jsonify({"muted": False}), 200
try:
r = requests.get(
f"http://127.0.0.1:{PORT_AGENT}/groups/{group_id}/mute_status",
headers=headers, timeout=10,
)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if not uid:
return jsonify({"sessions": []}), 200
try:
r = requests.get(
f"http://127.0.0.1:{PORT_AGENT}/groups/{group_id}/sessions",
headers=headers, timeout=15,
)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
return jsonify([]), 200
try:
print(f"[OASIS Proxy] Fetching topics from {OASIS_BASE_URL}/topics for user={user_id}")
r = requests.get(f"{OASIS_BASE_URL}/topics", params={"user_id": user_id}, timeout=10)
print(f"[OASIS Proxy] Response status: {r.status_code}, count: {len(r.json()) if r.text else 0}")
return jsonify(r.json()), r.status_code
except Exception as e: