Back to skill

Security audit

Korea metropolitan bus alerts

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent bus-alert purpose, but its persistent scheduled-agent prompts and DM-only delivery claims are not safely scoped or enforced.

Review this before installing if your Gateway agent has broad tools or if alerts could be registered from untrusted chat input. Use only trusted route, stop, and destination values, confirm cron job payloads carefully, and avoid running setup.py unless you are comfortable with it changing your user systemd Gateway override and restarting the service.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (3)

T01 · Skill Instruction Hijacking

Error
Location
scripts/cron_builder.py:69
Finding

Persistent Agent Prompt Injection Through Unvalidated Route Values

Content
View full analysis
List[str]: parts = [p.strip() for p in (s or "").split(",") if p.strip()] if not parts: raise ValueError("routes required") return parts def build_prompt(city: str, node: str, routes: List[str]) -> str: routes_csv = ",".join(routes) # The agent will run the deterministic script and then output a clean summary. return ( "You are running a scheduled TAGO bus arrival alert.\n" "- Do not reveal any secrets.\n" "- Query TAGO arrivals using the helper script and format a short message.\n\n" "Steps:\n" f"1) Run: python3 korea-metropolitan-bus-alerts/scripts/tago_bus_alert.py arrivals --city {city} --node {node} --routes {routes_csv}\n" "2) Parse the JSON and produce a human-friendly summary (Korean).\n" "3) Output ONLY the final message text (no code blocks).\n\n" "Format example:\n" "[버스 알림]\n" "- 535: 3분(2정거장 전) / 다음 12분\n" "- 730: 5분 / 다음 18분\n" ) ``` The generated prompt is registered as a recurring Agent task: ```python routes = parse_routes(input("Routes (comma-separated, e.g. 535,730): ").strip()) ... job = { "name": name, "schedule": {"kind": "cron", "cron": spec.to_cron(), "tz": spec.tz}, "sessionTarget": "isolated", "payload": { "kind": "agentTurn", "message": build_prompt(city, node, routes), "deliver": True, "bestEffortDeliver": True, "channel": channel, "to": to, }, } ... cmd = [ exe, "cron", "add", "--name", name, "--cron", spec.to_cron(), "--tz", spec.tz, "--session", "isolated", "--mes ...[truncated 2480 chars]
Remediation
View remediation
List[str]: routes = [part.strip() for part in value.split(",") if part.strip()] if not routes: raise ValueError("routes required") if len(routes) > 20: raise ValueError("too many routes") for route in routes: if not ROUTE_RE.fullmatch(route): raise ValueError(f"invalid route identifier: {route!r}") return routes ``` 2. Apply similarly strict allowlists to `city` and `node`, including length limits and rejection of whitespace and control characters. 3. Reject newlines, carriage returns, null bytes, leading option markers, and shell metacharacters in all values embedded in Agent instructions. 4. Avoid constructing executable commands inside natural-language prompts. Store structured arguments and invoke the deterministic helper through a fixed non-shell tool interface. 5. If an Agent prompt must contain external values, serialize them as clearly delimited JSON data and explicitly state that the data must never be interpreted as instructions. 6. Add tests covering newline injection, command separators, leading `--` values, oversized input, and embedded instruction text. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/rule_wizard.py:165
Finding

DM-Only Delivery Policy Is Not Enforced

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/setup.py:107
Finding

Custom Secret File Path Is Not Honored by the Systemd Override

Content
View full analysis
None: override = systemd_override_path(unit) override.parent.mkdir(parents=True, exist_ok=True) content = "[Service]\n" + f"EnvironmentFile=%h/.clawdbot/secrets/{env_file.name}\n" # If override exists, keep it simple: replace any previous EnvironmentFile line for our tago file. if override.exists(): old = override.read_text(encoding="utf-8", errors="replace").splitlines(True) new_lines: List[str] = [] in_service = False env_written = False for ln in old: if ln.strip().startswith("["): in_service = ln.strip().lower() == "[service]" if in_service and ln.strip().startswith("EnvironmentFile=") and "tago.env" in ln: # drop old tago env reference continue new_lines.append(ln) # Ensure we have a [Service] block and our EnvironmentFile text = "".join(new_lines) if "[Service]" not in text and "[service]" not in text.lower(): text = text.rstrip() + "\n\n[Service]\n" if f"EnvironmentFile=%h/.clawdbot/secrets/{env_file.name}" not in text: text = text.rstrip() + f"\nEnvironmentFile=%h/.clawdbot/secrets/{env_file.name}\n" override.wri ...[truncated 1974 chars]
Remediation
View remediation
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 (23)

Tainted flow: 'cmd' from input (line 205, user input) → subprocess.run (code execution)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

External input (network, user) flows to a code execution sink. This enables remote code execution or command injection.

Content

Scanner excerpt · scripts/rule_wizard.py (reported line 71)May include surrounding context.

python
def _run(cmd: List[str]) -> str:
    p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    if p.returncode != 0:
        raise RuntimeError(f"Command failed ({p.returncode}): {' '.join(cmd)}\n{p.stderr.strip()}")
    return p.stdout

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims an end-user alerting purpose but documents actions that auto-detect gateway units, write systemd overrides, store secrets, and restart the Gateway service. In context, those are materially more sensitive administrative operations than bus alert management, and a description-behavior mismatch here could be used to socially engineer approval for impactful local changes.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims an end-user alerting purpose but documents actions that auto-detect gateway units, write systemd overrides, store secrets, and restart the Gateway service. In context, those are materially more sensitive administrative operations than bus alert management, and a description-behavior mismatch here could be used to socially engineer approval for impactful local changes.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims an end-user alerting purpose but documents actions that auto-detect gateway units, write systemd overrides, store secrets, and restart the Gateway service. In context, those are materially more sensitive administrative operations than bus alert management, and a description-behavior mismatch here could be used to socially engineer approval for impactful local changes.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill claims an end-user alerting purpose but documents actions that auto-detect gateway units, write systemd overrides, store secrets, and restart the Gateway service. In context, those are materially more sensitive administrative operations than bus alert management, and a description-behavior mismatch here could be used to socially engineer approval for impactful local changes.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill advertises capabilities that include environment access, file write, network access, and shell execution, but it does not declare any explicit tool scope or allowed-tools boundary. In an agent ecosystem, missing least-privilege constraints increases the chance that the skill can invoke broader actions than users expect, especially because the document also instructs setup steps that modify local service configuration and restart services.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
72% confidence
Finding

The skill is explicitly designed to create persistent scheduled rules that continue running and delivering messages over time. Session persistence is expected for cron-based alerts, but it still introduces security and privacy risk because actions and messaging continue after the initiating interaction, and persistent jobs can be abused or forgotten if creation/deletion safeguards are weak.

Content

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

md
---
name: korea-metropolitan-bus-alerts
description: Create and manage scheduled bus arrival alerts using Korea TAGO (국토교통부) OpenAPI and Clawdbot cron. Use when a user wants to register weekday/weekend schedules like "평일 오전 7시, <정류소명>, <노선들>" and receive automatic arrival summaries via their configured Gateway messaging (DM only).
metadata:
  {
    "openclaw": {

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README tells users to place the TAGO service key directly in an export command and later source a file containing the secret, but it does not warn that inline shell commands may be recorded in shell history and that environment variables can be exposed to subprocesses, debug logs, or shared sessions. In this skill’s context, the key is an external API credential rather than a harmless value, so poor handling can lead to unauthorized API use, quota exhaustion, or key revocation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The generated prompt explicitly instructs the downstream agent to produce the summary in Korean. This is a natural-language locale policy constraint, and the file does not offer a language choice or explain that the skill is limited to Korean-only use.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/rule_wizard.py (reported line 71)May include surrounding context.

python
def _run(cmd: List[str]) -> str:
    p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    if p.returncode != 0:
        raise RuntimeError(f"Command failed ({p.returncode}): {' '.join(cmd)}\n{p.stderr.strip()}")
    return p.stdout

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
Features:
- Auto-detect the Gateway systemd unit (supports custom names)
- Prompt for TAGO_SERVICE_KEY (hidden input)
- Save to an env file (default: ~/.clawdbot/secrets/tago.env, chmod 600)
- Write/patch a systemd override EnvironmentFile=...
- Restart the Gateway service
- Smoke-test TAGO API call

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/set_tago_key.sh (reported line 12)May include surrounding context.

sh
Features:
- Auto-detect the Gateway systemd unit (supports custom names)
- Prompt for TAGO_SERVICE_KEY (hidden input)
- Save to an env file (default: ~/.clawdbot/secrets/tago.env, chmod 600)
- Write/patch a systemd override EnvironmentFile=...
- Restart the Gateway service
- Smoke-test TAGO API call

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/set_tago_key.sh (reported line 37)May include surrounding context.

sh
Features:
- Auto-detect the Gateway systemd unit (supports custom names)
- Prompt for TAGO_SERVICE_KEY (hidden input)
- Save to an env file (default: ~/.clawdbot/secrets/tago.env, chmod 600)
- Write/patch a systemd override EnvironmentFile=...
- Restart the Gateway service
- Smoke-test TAGO API call

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/set_tago_key.sh (reported line 40)May include surrounding context.

sh
Features:
- Auto-detect the Gateway systemd unit (supports custom names)
- Prompt for TAGO_SERVICE_KEY (hidden input)
- Save to an env file (default: ~/.clawdbot/secrets/tago.env, chmod 600)
- Write/patch a systemd override EnvironmentFile=...
- Restart the Gateway service
- Smoke-test TAGO API call

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/setup.py (reported line 11)May include surrounding context.

python
Features:
- Auto-detect the Gateway systemd unit (supports custom names)
- Prompt for TAGO_SERVICE_KEY (hidden input)
- Save to an env file (default: ~/.clawdbot/secrets/tago.env, chmod 600)
- Write/patch a systemd override EnvironmentFile=...
- Restart the Gateway service
- Smoke-test TAGO API call

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/setup.py (reported line 218)May include surrounding context.

python
Features:
- Auto-detect the Gateway systemd unit (supports custom names)
- Prompt for TAGO_SERVICE_KEY (hidden input)
- Save to an env file (default: ~/.clawdbot/secrets/tago.env, chmod 600)
- Write/patch a systemd override EnvironmentFile=...
- Restart the Gateway service
- Smoke-test TAGO API call

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/setup.py (reported line 36)May include surrounding context.

python
def run(cmd: List[str], *, check: bool = True) -> subprocess.CompletedProcess:
    return subprocess.run(cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check)


def list_gateway_units() -> List[str]:

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The setup script performs host-level discovery and modification of user systemd configuration, writes override files, and restarts a service. Even if intended for legitimate integration, this expands the skill from bus alerts into persistent local service reconfiguration, which can disrupt unrelated services or be abused if the chosen unit or env-file path is manipulated.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Restarting a systemd user service is a privileged operational action relative to the skill's stated purpose and can cause denial of service or unexpected behavior if the wrong unit is targeted. In a skill ecosystem, code that can reconfigure and restart host services increases trust requirements and blast radius beyond simple alert scheduling.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/setup.py (reported line 148)May include surrounding context.

python
if not script.exists():
        return

    p = subprocess.run(
        [sys.executable, str(script), "nearby-stops", "--lat", "37.5665", "--long", "126.9780"],
        text=True,
        stdout=subprocess.PIPE,

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The schedule mapping examples are presented only in Korean ("매일", "평일", "주말") even though the rest of the document is in English. This creates a language/locale constraint in the skill instructions without user opt-in or justification for why the skill is region- or language-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script prints a Korean-only status header ([버스 알림 테스트]) in a general-purpose CLI flow. This imposes a specific language on users without any opt-in or documented locale constraint, which matches the language/locale policy concern.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

Enumerating local user services is not directly harmful, but it gathers host configuration details unrelated to bus alerts and is part of a broader capability to identify and modify services. In a semi-trusted plugin or skill context, unnecessary host introspection increases attack surface and can aid misuse.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.