Back to skill

Security audit

投票鸭助手

Security checks for vulnerabilities and agentic risk

Overview

This voting skill largely does what it describes, but it stores a login token and can send that token to configurable API endpoints without host validation.

Review before installing. Use this only if you trust Toupiaoya and need its voting project features. Avoid setting TOUPIAOYA_API_BASE, EQXIU_AIGC_API_BASE, or --base-url unless you control the endpoint, and do not upload or submit confidential, regulated, or private voting content. Prefer an isolated Python environment and pinned dependencies.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/toupiaoya/constants.py:16
Finding

Persisted Access Token Can Be Disclosed to an Arbitrary Endpoint

Content
View full analysis
requests.Response: headers: dict[str, str] = dict(extra_headers or {}) if access_token: headers["X-Openclaw-Token"] = access_token return requests.post(url, json=dict(json_body), headers=headers or None, timeout=timeout) ``` ### Technical Analysis The API base URL can be supplied through the global `--base-url` option or the `TOUPIAOYA_API_BASE` and `EQXIU_AIGC_API_BASE` environment variables. No validation restricts the resulting dest ...[truncated 2880 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:203
Finding

Unpinned Third-Party Dependency Installation Creates Supply-Chain Risk

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • 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
Findings (35)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose focuses on voting workflows, but the skill also includes authentication, token validation, and persistent local credential storage behavior that are not clearly surfaced as core capabilities. This mismatch can mislead users and reviewers about the real security-sensitive behavior, especially around credential handling and local state changes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README instructs users to create voting projects via a remote HTTP API but does not clearly warn that titles, descriptions, group names, and option content will be transmitted to an external third-party service. This can lead users or downstream agents to send personal, confidential, or regulated data without informed consent, which is a real data-handling and privacy risk in an agent skill context.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill documents capabilities that imply network access, shell execution, local file reads/writes, and token handling, but it declares no explicit tool scope or permission boundaries. In an agent environment, this can cause the skill to be granted broader powers than users expect, increasing the risk of unauthorized file access, command execution, or outbound data transmission.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger phrases are extremely broad and overlap with ordinary user requests about voting, increasing the chance that the skill activates in contexts where the user did not intend credentialed network actions or remote data operations. Over-broad activation raises the risk of accidental invocation, unintended data transmission, and confused-deputy behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill explains how to obtain and reuse an access token, persist it locally, and perform uploads and data retrieval, but it does not clearly warn users that credentials will be stored and account/project data may be sent to third-party services. This reduces informed consent and increases the risk of inadvertent credential exposure or privacy violations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The login flow stores the X-Openclaw-Token in a local JSON config file, which creates credential-at-rest exposure if file permissions are weak, the host is shared, backups are accessible, or malware reads user config directories. In this skill’s context, the token appears to grant access to voting project management and uploaded materials, so compromise could let an attacker read or modify user content and activity data.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/toupiaoya/commands/project_cmd.py (reported line 12)May include surrounding context.

python
from toupiaoya.auth import resolve_token
from toupiaoya.config import load_config, token_from_config
from toupiaoya.create import ToupiaoyaCreator, parse_group_list
from toupiaoya.project_api import (
    add_project_group,
    add_project_choice,

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Confidence
55% confidence
Finding

Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.

Content

Scanner excerpt · scripts/toupiaoya/cos_upload.py (reported line 99)May include surrounding context.

python
key = object_key.lstrip("/")
    with local_path.open("rb") as fp:
        resp = client.put_object(Bucket=bucket, Body=fp, Key=key, EnableMD5=False)

    etag = (resp.get("ETag") or resp.get("Etag") or "").strip('"')
    out: dict[str, Any] = {

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 104)May include surrounding context.

md
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 123)May include surrounding context.

md
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 136)May include surrounding context.

md
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 139)May include surrounding context.

md
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 116)May include surrounding context.

md
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 135)May include surrounding context.

md
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 147)May include surrounding context.

md
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 251)May include surrounding context.

md
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 260)May include surrounding context.

md
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 271)May include surrounding context.

md
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/toupiaoya/commands/project_cmd.py (reported line 47)May include surrounding context.

python
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/toupiaoya/commands/project_cmd.py (reported line 228)May include surrounding context.

python
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/toupiaoya/create.py (reported line 15)May include surrounding context.

python
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/toupiaoya/create.py (reported line 57)May include surrounding context.

python
return None
    parsed = json.loads(group_list_text)
    if not isinstance(parsed, list):
        raise ValueError("--groupList 必须是 JSON 数组")
    return parsed

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The natural-language strings in the skill are exclusively Chinese, including the description and validation error, with no indication that the language is optional or required for a region-specific use case. That can violate language/locale policy when a skill imposes a language without user opt-in or documented justification.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · scripts/toupiaoya/http.py (reported line 36)May include surrounding context.

python
headers: dict[str, str] = dict(extra_headers or {})
    if access_token:
        headers["X-Openclaw-Token"] = access_token
    return requests.post(url, json=dict(json_body), headers=headers or None, timeout=timeout)


def post_multipart(

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This Python file performs numerous HTTP GET/POST requests using an access token, including fetching vote/view data and updating project choices/groups. Although the functions have minimal technical docstrings, there is no confirmation prompt, logging, print statement, or explicit user-facing warning in the file that project data and identifiers will be sent to external services.

Content

No source excerpt is available for this finding.