Back to skill

Security audit

cmclaw

Security checks for vulnerabilities and agentic risk

Overview

The skill fits its YouCloud advertising-analysis purpose, but it needs review because an unvalidated API-base override can redirect the API key and user prompts to another endpoint.

Install only if you intend to send advertising strategy prompts and related account context to YouCloud. Keep YOUCLOUD_API_KEY private, do not set DAM_API_BASE unless you fully trust the destination, and be aware that CLI output may expose user, team, and session identifiers in logs.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
skill.py:168
Finding

Unrestricted API Base Override Enables Credential and User-Data Exfiltration

Content
View full analysis

Vulnerability Details

File Location: skill.py:35-50, skill.py:53-98, and skill.py:168-178
Vulnerability Type: Unvalidated network destination for sensitive authenticated requests
Risk Level: High

The DAM_API_BASE environment variable controls the destination of authenticated API requests without any validation or allowlisting. Both requests send the YOUCLOUD_API_KEY in the Authorization header. The chat request also sends the user's question, user ID, and team ID.

Vulnerable Code

python
def _get_identity(base: str, api_key: str) -> Tuple[int, str]:
    """Call userInfo:get to retrieve user_id / team_id."""
    url = f"{base}/api/rpc/user/v1/user/userInfo:get"
    req = urllib.request.Request(
        url,
        headers={"Authorization": f"YC_API_KEY {api_key}"}
    )
    try:
        with urllib.request.urlopen(
            req, timeout=30, context=_SSL_CONTEXT
        ) as resp:
            data = json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        raise DamClawError(
            f"userInfo:get failed status={e.code} "
            f"body={e.read().decode('utf-8', errors='replace')}"
        )
    except urllib.error.URLError as e:
        raise DamClawError(f"userInfo:get network error: {e.reason}")

    return int(data["user_id"]), str(data["team_id"])
python
def cmclaw_chat(
    question: str,
    user_id: int,
    team_id: str,
    api_key: str,
    base: str = DEFAULT_BASE,
    session_id: Optional[str] = None,
    chat_mode: Optional[int] = None,
) -> Tuple[str, str]:
    body = {"input": question, "user_id": user_id, "team_id": team_id}

    url = f"{base}/api/rpc/ai/claw/v1/chat"
    payload = json.dumps(body).encode("utf-8")
    req = urllib.request.Request(
        url,
        data=payload,
        headers={
            "Authorization": f"YC_API_KEY {api_key}",
            "Conte
...[truncated 3950 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the DAM_API_BASE override from production builds and always use the fixed official HTTPS origin when alternate environments are not required.
  2. If multiple environments are required, select among a hardcoded allowlist of exact origins rather than accepting an arbitrary URL. For example, permit only explicitly approved YouCloud production and staging hosts.
  3. Parse the configured value with urllib.parse.urlsplit and enforce all of the following:
    • The scheme must be https.
    • The normalized hostname must exactly match an approved hostname.
    • Embedded usernames and passwords must be rejected.
    • Unexpected ports, query strings, and fragments must be rejected.
    • The path must be empty or match the expected deployment prefix.
  4. Disable automatic redirects for authenticated requests, or validate every redirect target and never forward the Authorization header across origins.
  5. Build API URLs from a validated origin and fixed path constants. Do not concatenate an untrusted value directly into an authenticated request URL.
  6. Remove the unconditional identity log at skill.py:176. If diagnostic logging is necessary, make it explicitly opt-in and redact account and tenant identifiers.
  7. Treat environment configuration as security-sensitive deployment input. Restrict who can edit service manifests, CI variables, container environment values, and process launch configuration.
  8. Add tests confirming that HTTP URLs, unknown hosts, embedded credentials, alternate ports, and cross-origin redirects are rejected before any request containing the API key is sent.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill declares access to environment variables and performs outbound API calls, but it does not define any explicit tool scope or allowed-tools boundary. That increases the risk of over-broad execution privileges, makes review harder, and can allow future code changes to use sensitive capabilities without a clear policy contract.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger conditions are broad natural-language phrases like creative analysis, inspiration, and strategy exploration, which can cause the skill to activate for ordinary user requests that only loosely match its purpose. In a skill with network access and credentialed API use, over-triggering can send user prompts or business data to an external service without sufficiently explicit user intent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
79% confidence
Finding

The output instructions require the model to return the full markdown result as-is and then append a fixed Chinese label, "对话详情:{拼接的链接}". This imposes a specific locale in the user-facing response without any stated user preference, language selection mechanism, or justification for a Chinese-only output convention.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This file presents all operational instructions, warnings, and examples exclusively in Chinese, which can amount to a language/locale policy violation when users or integrators are not given an opt-in or alternative language. The policy allows justified region-specific constraints, but this document does not explicitly state that the skill is Chinese-only or limited to a China-specific audience.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/cm-claw-api.md (reported line 184)May include surrounding context.

bash
# 环境变量:YOUCLOUD_API_KEY / DAM_USER_ID / DAM_TEAM_ID(后两者由 userInfo:get 返回)
curl -N -X POST https://console.dam.youcloud.com/api/rpc/ai/claw/v1/chat \
  -H "Authorization: YC_API_KEY $YOUCLOUD_API_KEY" \
  -H "Content-Type: application/json; charset=utf-8" \
  --max-time 650 \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/cm-claw-api.md (reported line 199)May include surrounding context.

python
import json, requests

resp = requests.post(
    "https://console.dam.youcloud.com/api/rpc/ai/claw/v1/chat",
    headers={"Authorization": f"YC_API_KEY {api_key}"},
    json={"input": question, "user_id": int(uid), "team_id": tid, "chat_mode": 2},  # uid 转 int

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/cm-claw-api.md (reported line 199)May include surrounding context.

python
import json, requests

resp = requests.post(
    "https://console.dam.youcloud.com/api/rpc/ai/claw/v1/chat",
    headers={"Authorization": f"YC_API_KEY {api_key}"},
    json={"input": question, "user_id": int(uid), "team_id": tid, "chat_mode": 2},  # uid 转 int

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The module docstring and usage guidance are entirely in Chinese, and the CLI prompt/help strings later in the file are also Chinese-only. This imposes a specific language on users without opt-in or justification, which matches the language/locale policy violation category.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The command-line entrypoint uses Chinese-only help text, default prompt content, and status messages. Because there is no option for another language or documented locale restriction, this is a natural-language policy issue.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The function documentation describes line-by-line streaming semantics for an NDJSON response, including heartbeat handling during an active stream. However, the implementation at L100-L103 calls resp.read() and only then splits lines, which means it does not actually consume incrementally and will wait for the full response body before parsing.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The comments describe '逐行读取流式响应' and 'chunked transfer', but immediately note that resp.read() blocks until the stream ends and then use read().splitlines(). This contradicts the claimed streaming behavior because the code processes only after the entire response is received.

Content

No source excerpt is available for this finding.