Back to skill

Security audit

DNFM周本进度追踪

Security checks for vulnerabilities and agentic risk

Overview

This is a small local game-progress tracker whose file writes are disclosed and limited, with some non-malicious quality and documentation issues to review.

Before installing, be aware that this tracker stores and mutates progress in fixed local JSON files and may erase newly entered progress if invoked repeatedly on a refresh day after 06:00. The unrelated MLOL documentation should be ignored or removed unless you intentionally want that reference material included.

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

Warning
Location
scripts/tracker.py:69
Finding
Repeated Refresh-Day Reset Causes Progress Data Loss<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tracker.py`, lines 69–91 **Vulnerability Type**: Improper state validation resulting in repeated destructive resets **Risk Level**: Medium ### Vulnerable Code ```python for name, config in events.items(): if not config.get("enabled", True): continue key = config["key"] refresh_day = config["refresh_day"] # 判断今天是否是刷新日,且当前时间超过6点 if weekday == refresh_day and now.hour >= refresh_hour: # 重置进度 data["progress"][key] = {"done": 0, "total": config["total"]} data["last_reset"] = data.get("last_reset", {}) data["last_reset"][key] = now.strftime("%Y-%m-%d") save_progress(data) return data ``` ### Technical Analysis The reset routine records the date of the latest reset in `data["last_reset"][key]`, but it never checks that value before resetting progress. Therefore, on an event's configured refresh day, every invocation at or after 06:00 overwrites the event's progress with zero. The main program calls `check_reset()` for every command. Several command handlers, including status and update operations, also invoke the reset routine. Consequently, progress entered after the intended weekly reset can be silently deleted by a subsequent invocation on the same day. This violates the intended once-per-refresh-cycle behavior and creates a local data-integrity flaw. No external code execution, privilege escalation, or unauthorized system access is enabled by this issue. ### Attack Path 1. The system reaches an event's configured refresh day and the local time passes 06:00. 2. A user invokes the tracker, causing the expected weekly reset. 3. The user records new progress later that day with `tracker.py --update`. 4. A local user or automated process invokes any tracker command again. 5. `check_reset()` sees only that the weekday and hour match the reset condition. 6 ...[truncated 967 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Before resetting an event, compare its stored reset date with the current date and perform the reset only when they differ. ```python today_string = now.strftime("%Y-%m-%d") last_reset = data.setdefault("last_reset", {}) progress = data.setdefault("progress", {}) changed = False for name, config in events.items(): if not config.get("enabled", True): continue key = config["key"] refresh_day = config["refresh_day"] if ( weekday == refresh_day and now.hour >= refresh_hour and last_reset.get(key) != today_string ): progress[key] = { "done": 0, "total": config["total"], } last_reset[key] = today_string changed = True if changed: save_progress(data) ``` Additional hardening measures: 1. Save the progress file once after processing all events instead of once per event. 2. Write updates atomically by creating a securely permissioned temporary file in the destination directory and replacing the original file with `os.replace()`. 3. Validate that loaded JSON objects contain dictionaries for `progress` and `last_reset` before using them. 4. Catch specific exceptions such as `FileNotFoundError` and `json.JSONDecodeError` rather than suppressing every exception. 5. Add regression tests for: - Multiple calls after 06:00 on the same refresh day. - An update performed after the daily reset. - A status request following that update. - The next scheduled refresh cycle. - Multiple events sharing the same refresh day. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill documentation explicitly states it will read and write local files under /root/.openclaw/workspace/dnfm-tracker, but the manifest declares no permissions or allowed-tools scope. That creates an authorization gap: a reviewer or runtime may not have clear visibility that the skill persists and mutates filesystem state, increasing the chance of unintended file access or unsafe deployment assumptions.

Missing User Warnings

Low
Confidence
81% confidence
Finding
This markdown file applies to SQP-2, and it describes an HTTP API based on axios without any user-facing warning about privacy, data transmission, or external requests. Because the feature can send data over the network and the document presents it as a core capability, a brief disclosure would improve user awareness.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The file describes operations to open apps and download apps, which can change user context or initiate software retrieval, but it does not include any cautionary note. Under SQP-2 for markdown files, documentation should warn about behaviors that may affect system integrity or user expectations.

Missing User Warnings

Low
Confidence
86% confidence
Finding
The sharing section exposes link and image sharing capabilities but provides no warning about potential disclosure of user data or content to third parties. For markdown files, SQP-2 expects warnings when documented behavior could affect privacy.

Static analysis

No suspicious patterns detected.