Back to skill

Security audit

teamclawtestv101

Security checks across malware telemetry and agentic risk

Overview

The skill broadly matches its advertised multi-agent assistant purpose, but it gives a web-facing AI agent powerful local command, file, scheduling, and credential-backed authority that needs careful review before use.

Install only in a trusted local environment, use throwaway or low-privilege credentials, avoid public tunneling unless you have reviewed the auth model, and do not grant this skill access to sensitive files or production systems until command execution, credential handling, CSRF protection, and binary/dependency verification are tightened.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (92)

Tainted flow: 'LOCAL_OPENAI_COMPLETIONS_URL' from os.getenv (line 28, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
# 直接透传请求体和 Authorization header 到后端
    auth_header = request.headers.get("Authorization", "")
    try:
        r = requests.post(
            LOCAL_OPENAI_COMPLETIONS_URL,
            json=request.get_json(silent=True),
            headers={
Confidence
95% confidence
Finding
The /v1/chat/completions proxy blindly forwards any Authorization header and request body from the browser to the backend agent without additional validation, CSRF protection, or origin restrictions. If the frontend is exposed beyond a trusted boundary, this creates a credential-forwarding proxy that can be abused to invoke privileged backend actions and relay sensitive prompt/file content.

Tainted flow: 'LOCAL_LOGIN_URL' from os.getenv (line 20, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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
Confidence
93% confidence
Finding
User credentials are accepted by the Flask app and forwarded to a backend login service, then later stored server-side in session state. Combined with the lack of visible session hardening settings and the app's role as a browser-facing proxy, this increases credential exposure risk if the Flask session is stolen or the app is accessed cross-site.

Tainted flow: 'LOCAL_OPENAI_COMPLETIONS_URL' from os.getenv (line 28, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
}

    try:
        r = requests.post(
            LOCAL_OPENAI_COMPLETIONS_URL,
            json=openai_payload,
            headers={"Authorization": f"Bearer {user_id}:{password}"},
Confidence
96% confidence
Finding
This deprecated proxy forwards user_id:password as a Bearer credential to the backend on each request, effectively turning raw credentials into reusable API tokens. If logs, client storage, or intermediaries expose that header, an attacker can directly impersonate the user to the backend agent.

Tainted flow: 'LOCAL_OPENAI_COMPLETIONS_URL' from os.getenv (line 28, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
}

    try:
        r = requests.post(
            LOCAL_OPENAI_COMPLETIONS_URL,
            json=openai_payload,
            headers={"Authorization": f"Bearer {user_id}:{password}"},
Confidence
96% confidence
Finding
The streaming proxy similarly forwards raw credentials in an Authorization header and relays potentially sensitive multimodal payloads to the backend. This expands the blast radius because prompts, uploaded files, images, and audio all transit through a credential-bearing proxy path.

Tainted flow: 'LOCAL_AGENT_CANCEL_URL' from os.getenv (line 19, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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
Confidence
90% confidence
Finding
The cancel endpoint forwards stored raw credentials to the backend without CSRF defenses. An attacker able to trigger authenticated cross-site requests could disrupt active jobs or conversations for the victim user.

Tainted flow: 'LOCAL_TTS_URL' from os.getenv (line 25, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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
Confidence
90% confidence
Finding
The TTS proxy forwards authenticated user text to a backend service using stored credentials. This can expose sensitive model output or user-entered content to additional services and broadens the number of endpoints that receive user secrets.

Tainted flow: 'LOCAL_TOOLS_URL' from os.getenv (line 21, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
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
Confidence
88% confidence
Finding
The tools proxy exposes backend capability metadata through a browser-accessible endpoint protected only by an internal token in process memory. If the frontend is reachable by untrusted users, this leaks enabled tools and increases the attacker's understanding of available backend actions.

Tainted flow: 'LOCAL_SESSIONS_URL' from os.getenv (line 22, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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
Confidence
92% confidence
Finding
The sessions listing endpoint forwards raw credentials to enumerate user session metadata. While intended functionality, it contributes to credential overuse and exposes conversation structure/history through a browser-facing proxy.

Tainted flow: 'PORT_AGENT' from os.getenv (line 16, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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,
Confidence
90% confidence
Finding
Polling all session statuses with raw credentials expands authenticated backend access and reveals operational state for all sessions. In a multi-agent/orchestration context, that metadata can be sensitive and useful for abuse timing or disruption.

Tainted flow: 'LOCAL_SESSION_HISTORY_URL' from os.getenv (line 23, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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
Confidence
94% confidence
Finding
The session history endpoint forwards credentials and returns full message history, including potentially sensitive prompts, tool outputs, and uploaded content references. If the web session is compromised or cross-site requests are possible, this becomes a straightforward conversation exfiltration path.

Tainted flow: 'LOCAL_SESSION_STATUS_URL' from os.getenv (line 26, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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
Confidence
89% confidence
Finding
This endpoint exposes whether a session has new messages by forwarding credentials to the backend. While not severe alone, it leaks workflow state and contributes to an unnecessary surface area of credential-backed browser endpoints.

Tainted flow: 'LOCAL_DELETE_SESSION_URL' from os.getenv (line 24, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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
Confidence
94% confidence
Finding
Deleting sessions is a state-changing action performed through a browser-facing proxy that reuses stored raw credentials and lacks CSRF protection. A forged request could destroy user conversation history irreversibly.

Tainted flow: 'PORT_AGENT' from os.getenv (line 16, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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
Confidence
91% confidence
Finding
Creating groups forwards browser-supplied JSON and an Authorization header derived from session credentials to the backend. Without CSRF protection and with credential material also stored client-side, an attacker could create or manipulate group-chat structures under the victim account.

Tainted flow: 'PORT_AGENT' from os.getenv (line 16, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
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
Confidence
90% confidence
Finding
Fetching group details exposes potentially sensitive group membership and message context via a credential-backed browser proxy. In this application, group chats can include agent sessions and orchestration context, making unauthorized reads more damaging than ordinary chat metadata.

Tainted flow: 'PORT_AGENT' from os.getenv (line 16, credential/environment) → requests.put (network output)

Critical
Category
Data Flow
Content
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
Confidence
92% confidence
Finding
Updating groups is a state-changing proxy action that accepts arbitrary JSON and forwards it with authenticated headers. This could be abused to add/remove members or alter access if an attacker can induce requests in the victim's browser.

Tainted flow: 'PORT_AGENT' from os.getenv (line 16, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
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,
Confidence
90% confidence
Finding
Incremental message retrieval leaks live group-chat content through the frontend proxy. Because groups can include autonomous agent sessions, unauthorized access may disclose internal agent outputs, coordination, or sensitive user instructions.

Tainted flow: 'PORT_AGENT' from os.getenv (line 16, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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,
Confidence
92% confidence
Finding
Posting group messages forwards attacker-controlled JSON into authenticated backend actions, potentially triggering agent behavior via mentions and automation. In a multi-agent orchestration product, unauthorized message injection can influence downstream agent actions, not just chat content.

Tainted flow: 'PORT_AGENT' from os.getenv (line 16, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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,
        )
Confidence
88% confidence
Finding
Muting a group is a state-changing action reachable through the browser proxy without CSRF protections. This enables denial-of-service against collaborative agent/group workflows if a victim can be tricked into issuing the request.

Tainted flow: 'PORT_AGENT' from os.getenv (line 16, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
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,
        )
Confidence
88% confidence
Finding
Unmuting has the same issue as muting: authenticated state changes are exposed through the browser-facing proxy with weak session design. Attackers could manipulate workflow state by forcing toggles.

Tainted flow: 'PORT_AGENT' from os.getenv (line 16, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
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,
        )
Confidence
89% confidence
Finding
This endpoint enumerates sessions available to join a group, exposing session metadata through a browser proxy. In this system that metadata maps to agent sessions, which can reveal internal structure and enable targeted abuse.

Tainted flow: 'url' from os.getenv (line 6088, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
try:
        url = f"{OASIS_BASE_URL}/topics/{topic_id}"
        print(f"[OASIS Proxy] Fetching topic detail from {url} for user={user_id}")
        r = requests.get(url, params={"user_id": user_id}, timeout=10)
        print(f"[OASIS Proxy] Detail response status: {r.status_code}")
        return jsonify(r.json()), r.status_code
    except Exception as e:
Confidence
86% confidence
Finding
The topic detail proxy incorporates a path parameter into a backend URL and returns full discussion data. While the host is fixed, the route exposes potentially sensitive multi-expert discussion content and should be treated as a protected data-exfiltration surface.

Tainted flow: 'OASIS_BASE_URL' from os.getenv (line 33, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
if not user_id:
        return jsonify({"error": "未登录"}), 401
    try:
        r = requests.get(
            f"{OASIS_BASE_URL}/topics/{topic_id}/stream",
            params={"user_id": user_id},
            stream=True, timeout=300,
Confidence
87% confidence
Finding
Streaming OASIS discussions exposes live multi-expert outputs through the frontend. In an orchestration product, those discussions may contain strategic prompts, internal reasoning, or operational plans, making unauthorized streaming access more sensitive than ordinary chat.

Tainted flow: 'OASIS_BASE_URL' from os.getenv (line 33, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
if not user_id:
        return jsonify({"error": "未登录"}), 401
    try:
        r = requests.post(f"{OASIS_BASE_URL}/topics/{topic_id}/purge", params={"user_id": user_id}, timeout=10)
        return jsonify(r.json()), r.status_code
    except Exception as e:
        return jsonify({"error": str(e)}), 500
Confidence
89% confidence
Finding
Purging OASIS topics is a destructive state-changing action exposed through the browser proxy. Without explicit CSRF protection and stronger authorization hardening, an attacker could delete discussion records for the victim user.

Tainted flow: 'OASIS_BASE_URL' from os.getenv (line 33, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
if not data:
        return jsonify({"error": "No data"}), 400
    try:
        r = requests.post(
            f"{OASIS_BASE_URL}/experts/user",
            json={"user_id": user_id, **data},
            timeout=10,
Confidence
90% confidence
Finding
Creating custom experts lets authenticated users send arbitrary persona/instruction content to the OASIS service. In a multi-agent orchestration system, this can materially alter downstream agent behavior and should be tightly controlled because browser compromise could inject malicious expert personas.

Tainted flow: 'LOCAL_OPENAI_COMPLETIONS_URL' from os.getenv (line 28, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
"session_id": data.get("target_session_id") or "visual_orchestrator",
            "temperature": 0.3,
        }
        resp = requests.post(LOCAL_OPENAI_COMPLETIONS_URL, json=payload, headers=headers, timeout=60)
        if resp.status_code != 200:
            return jsonify({"prompt": prompt, "error": f"Agent returned HTTP {resp.status_code}: {resp.text[:500]}", "agent_yaml": None})
Confidence
94% confidence
Finding
The orchestration feature sends generated prompts to the backend agent and can persist returned YAML, effectively giving browser users a path to create executable orchestration artifacts under their account. If abused, this can influence subsequent agent workflows and store attacker-crafted plans for later execution.

VirusTotal

66/66 vendors flagged this skill as clean.

View on VirusTotal