Back to skill

Security audit

九号数据展示

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed read-only Ninebot vehicle reporting helper, with expected handling of local vehicle data and map services.

Install only if you are comfortable letting a local agent read your Ninebot vehicle status, rides, and location through an already authenticated ninecli session. Map and ride-visualization features may send location or route-area data to third-party map services; use privacy=off or avoid map commands if that is not acceptable.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (37)

Credential Access

High
Category
Privilege Escalation
Content
# Ninebot Show Skill

Read-only Agent Skill for Ninebot/九号 electric vehicles. It uses a locally authenticated `ninecli` session. Never ask the user to paste a Ninebot password, SMS verification code, access token, cookie, or BLE secret into chat.

## Use this skill for
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
return value

    explicit = os.environ.get("NINEBOT_ENV_FILE", "").strip()
    candidates = [Path(explicit).expanduser()] if explicit else [CONFIG_DIR / ".env"]
    for env_file in candidates:
        try:
            lines = env_file.read_text(encoding="utf-8", errors="ignore").splitlines()
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# Optional. Copy to ~/.config/ninebot-show-skill/.env and fill locally.
AMAP_WEB_KEY=
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# Optional. Copy to ~/.config/ninebot-show-skill/.env and fill locally.
AMAP_WEB_KEY=
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The skill documentation is written entirely in Chinese, including setup and operational instructions, with no indication that another language is supported or that the Chinese-only presentation is an intentional, justified locale constraint. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill advertises shell, network, file read/write, and environment access but does not declare any explicit tool scope or allowed-tools boundary. That creates unnecessary ambient authority: an agent platform may grant broader capabilities than needed, increasing the chance of unintended command execution, local file access, or data exfiltration if the skill is invoked in the wrong context.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
# Ninebot Show Skill

Read-only Agent Skill for Ninebot/九号 electric vehicles. It uses a locally authenticated `ninecli` session. Never ask the user to paste a Ninebot password, SMS verification code, access token, cookie, or BLE secret into chat.

## Use this skill for
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Session Persistence

Medium
Category
Rogue Agent
Content
.venv/bin/ninecli vehicles --json
```

Write the returned vehicle `wnumber` into:

```text
~/.config/ninebot-show-skill/config.json
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.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The installer copies the skill into agent-specific directories and immediately executes a setup script from that copied location without any prompt, dry-run, or explicit disclosure of what setup will do. Even though this is a common installation pattern, it creates a trust boundary problem: running install.sh implicitly runs additional code, which increases the chance of unintended local changes or abuse if the package contents are modified or the user expects a copy-only install.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def read_status(sn: str) -> tuple[dict, float, float]:
    out = subprocess.run(ninecli_argv(SKILL_DIR, "status", sn, "--json"), capture_output=True, text=True, timeout=60)
    if out.returncode != 0:
        raise SystemExit("ninecli status 失败,请检查登录状态和 SN")
    data = json.loads(out.stdout)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def coords() -> tuple[float, float]:
    py = str(PYTHON if PYTHON.exists() else Path(sys.executable))
    out = subprocess.run([py, str(LOCATE), "--privacy", "coordinates", "--json"], capture_output=True, text=True, timeout=120)
    if out.returncode != 0:
        raise SystemExit(out.stderr.strip() or "定位失败")
    data = json.loads(out.stdout)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This Python file contains user-facing natural-language output, errors, help text, and report content almost entirely in Chinese, including generated report strings and CLI messages. That enforces a specific language/locale for all users without any visible opt-in, selection mechanism, or documented justification for a China-only deployment.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_process(args: list[str], timeout: int = 35) -> subprocess.CompletedProcess[str]:
    return subprocess.run(
        args,
        capture_output=True,
        text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def load_ride(ride_id, sn):
    raw = subprocess.run(ninecli_argv(SKILL_DIR, "travel", sn, "--detail", ride_id, "--json"),
                         capture_output=True, text=True, timeout=90).stdout
    d = json.loads(raw)
    pts = []
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def today_ride_ids(sn):
    raw = subprocess.run(ninecli_argv(SKILL_DIR, "travel", sn, "--json"), capture_output=True, text=True, timeout=90).stdout
    d = json.loads(raw)
    today = dt.date.today()
    ids = []
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def latest_ride():
    out = subprocess.run(ninecli_argv(SKILL_DIR, "travel", SN, "--json"), capture_output=True, text=True, timeout=60)
    rs = json.loads(out.stdout)["list"]
    return rs[0]
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def ride_detail(tid):
    out = subprocess.run(ninecli_argv(SKILL_DIR, "travel", SN, "--detail", tid, "--json"),
                         capture_output=True, text=True, timeout=60)
    return json.loads(out.stdout)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The function fetches OpenStreetMap tiles based on the min/max longitude and latitude of the user's ride path, which discloses the geographic area of a recent trip to an external service. In a vehicle-status skill handling sensitive mobility data, this is a real privacy issue because home/work areas and travel habits may be inferred, and the skill description does not indicate a clear user-facing warning or consent flow for that network transmission.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The script emits user-facing messages entirely in Chinese, including the error message at L12 and setup instructions through L45. This imposes a specific language on all users without any opt-in or documented locale constraint, which matches the language/locale policy violation criteria.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
"$VENV/bin/python" -m pip install -r "$SKILL_DIR/requirements.txt"

mkdir -p "$APP_CONFIG_DIR"
chmod 700 "$APP_CONFIG_DIR" 2>/dev/null || true
if [[ ! -f "$APP_CONFIG" ]]; then
  cp "$SKILL_DIR/templates/config.example.json" "$APP_CONFIG"
  chmod 600 "$APP_CONFIG" 2>/dev/null || true
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
chmod 700 "$APP_CONFIG_DIR" 2>/dev/null || true
if [[ ! -f "$APP_CONFIG" ]]; then
  cp "$SKILL_DIR/templates/config.example.json" "$APP_CONFIG"
  chmod 600 "$APP_CONFIG" 2>/dev/null || true
  echo "已创建配置: $APP_CONFIG"
else
  echo "保留现有配置: $APP_CONFIG"
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code hard-codes Chinese-language strings in the module docstring, error messages, and all printed status text, which imposes a specific language/locale on users. Under the policy, locale-specific behavior should either be optional via user choice or clearly documented as a justified regional constraint.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_json(cmd: list[str], timeout: int = 180) -> dict:
    out = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
    if out.returncode != 0:
        raise SystemExit(out.stderr.strip() or out.stdout.strip() or "命令执行失败")
    return json.loads(out.stdout)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The example config uses a Chinese vehicle name, a Shanghai location, and an Asia/Shanghai timezone as defaults. This natural-language and locale-specific setup may steer the skill toward a specific language/region without user opt-in or justification, which matches the language/locale policy concern.

Vague Triggers

Low
Confidence
80% confidence
Finding
The manifest description says to use the skill when the user asks about 'rides, smart service, daily reports, or vehicle visualizations' without enumerating tighter trigger phrases or exclusions. Terms like 'daily reports' and 'rides' are broad enough that they could match unrelated conversation unless the surrounding system already constrains activation to Ninebot-specific context.

Static analysis

No suspicious patterns detected.