Back to skill

Security audit

Lemnos Cost Guard

Security checks for vulnerabilities and agentic risk

Overview

The skill is a cost-tracking utility, but it overstates automatic budget enforcement and includes scripts with broad session-log access plus an unsafe snapshot deletion path.

Review before installing. This skill is not clearly malicious and I found no network exfiltration or remote-code loading, but it needs sensitive access to OpenClaw session logs and has an unsafe local file deletion bug. Treat its budget alerts as advisory, not enforced limits, and avoid putting secrets or customer details in task descriptions until reporting output is redacted and snapshot IDs are validated.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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/task_logger.py:113
Finding

Path Traversal Enables JSON File Access and Deletion Outside the Snapshot Directory

Content
View full analysis
dict: snap_path = os.path.join(SNAPSHOT_DIR, f"{snap_id}.json") with open(snap_path) as f: return json.load(f) def delete_snapshot(snap_id: str): snap_path = os.path.join(SNAPSHOT_DIR, f"{snap_id}.json") if os.path.exists(snap_path): os.remove(snap_path) ``` The vulnerable functions are reached directly through the `end` command: ```python def cli_end(snap_id: str, status: str = "ok"): snap = load_snapshot(snap_id) after = read_session_totals() entry = log_task( task_type=snap["task_type"], description=snap["description"], before=snap["totals_before"], after=after, timestamp_start=snap["timestamp_start"], timestamp_end=datetime.now(timezone.utc).isoformat(), status=status ) delete_snapshot(snap_id) print(f"[task_logger] LOGGED: {snap['task_type']} | ${entry['cost_usd']:.4f} | " f"{entry['calls']} calls | {entry['output_tokens']:,} out tokens") ``` ```python elif cmd == "end": snap_id = sys.argv[2] status = sys.argv[3] if len(sys.argv) > 3 else "ok" cli_end(snap_id, status) ``` ### Technical Analysis The `snap_id` command-line argument is incorporated into a filesystem path without validation or canonicalization. The code assumes that the value is an eight-character UUID fragment, but this constraint is only applied when the program creates a snapshot. It is not enforced when a snapshot is loaded or deleted. An attacker can supply path separators, `..` components, or an absolute path. In Python, if the later operand supplied to `os.path.join()` is absolute, the preceding `SNAPSHOT_DIR` is discarded. The `.json` suffix limits the affected filenames to JSON paths, but it ...[truncated 2338 chars]
Remediation
View remediation
str: if not SNAPSHOT_ID_RE.fullmatch(snap_id): raise ValueError("Invalid snapshot ID") return snap_id ``` 2. Resolve the candidate path and verify that it remains under the snapshot directory: ```python def snapshot_path(snap_id: str) -> str: validate_snapshot_id(snap_id) base = os.path.realpath(SNAPSHOT_DIR) candidate = os.path.realpath(os.path.join(base, f"{snap_id}.json")) if os.path.commonpath([base, candidate]) != base: raise ValueError("Snapshot path escapes snapshot directory") return candidate ``` 3. Use the validated helper consistently in `save_snapshot()`, `load_snapshot()`, and `delete_snapshot()`. 4. Track snapshots created by the current process or maintain a trusted index. Refuse to delete a file unless its identifier is present in that trusted state. 5. Reject symlinks where supported. Open files using secure flags such as `O_NOFOLLOW`, and verify the opened file is a regular file before reading or deleting it. 6. Validate the JSON schema after loading, including the types and permitted values of every field. 7. Run the utility under a dedicated, unprivileged account with write access only to its log and snapshot directories. 8. Add tests covering absolute paths, nested traversal, encoded or mixed path separators, symlinks, malformed IDs, and incompatible snapshot documents. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/auto_cost_report.py:39
Finding

Cost Reporting Processes All Main-Agent Session Records Without Least-Privilege Scoping

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Describing a manual CLI-based logger as a real-time monitoring and guardrail system can cause operators to assume spend limits and reports are being enforced automatically when they are not. In a cost-management context, that gap is dangerous because failure is silent: nothing blocks excessive API usage unless the user remembers to invoke the scripts correctly.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

Describing a manual CLI-based logger as a real-time monitoring and guardrail system can cause operators to assume spend limits and reports are being enforced automatically when they are not. In a cost-management context, that gap is dangerous because failure is silent: nothing blocks excessive API usage unless the user remembers to invoke the scripts correctly.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Describing a manual CLI-based logger as a real-time monitoring and guardrail system can cause operators to assume spend limits and reports are being enforced automatically when they are not. In a cost-management context, that gap is dangerous because failure is silent: nothing blocks excessive API usage unless the user remembers to invoke the scripts correctly.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Describing a manual CLI-based logger as a real-time monitoring and guardrail system can cause operators to assume spend limits and reports are being enforced automatically when they are not. In a cost-management context, that gap is dangerous because failure is silent: nothing blocks excessive API usage unless the user remembers to invoke the scripts correctly.

Content

No source excerpt is available for this finding.

External Model or Provider Selection

High
Category
Excessive Agency
Confidence
90% confidence
Finding

Skill selects an external model or provider that may use a different account or billing plan than the operator expects. Undisclosed model switches can cause unexpected cost or quota consumption.

Content

Scanner excerpt · scripts/track_cost.py (reported line 4)May include surrounding context.

python
#!/usr/bin/env python3
"""
track_cost.py — Log a cost entry to the daily cost log.
Usage: python3 track_cost.py --task "email batch" --input 45000 --output 1200 --model claude-sonnet-4-6
"""
import json, argparse, os
from datetime import datetime, timezone

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest description says to use the skill not only for specific actions like generating cost reports, but also broadly 'when a user asks about API costs, budget status, or why costs are high.' Those phrases are common conversational topics and the file does not provide exclusion conditions or tighter trigger boundaries, increasing the risk of unintended invocation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The full report prints the raw task description field directly to stdout, which can expose sensitive operational content, customer data, prompts, or internal notes to anyone who can run the script or view its output. In a cost-monitoring skill, task descriptions are especially likely to contain business context, making accidental disclosure a realistic confidentiality risk even if there is no active attacker.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The description mixes English instructions with Chinese text ('适用于一人公司和AI运营团队的实时成本监控工具。防止API成本失控。328+次安装。') but does not indicate that multilingual output is optional or user-selected. This can violate language/locale policy when a skill imposes a language choice without opt-in or justification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.