Back to skill

Security audit

龙虾文游系统

Security checks for vulnerabilities and agentic risk

Overview

This is a Chinese text-adventure skill with disclosed local save behavior and no hidden installer, network calls, or destructive actions; users should be mindful of saved gameplay content and extension code.

Installers should treat this as a local game skill. Do not put secrets or sensitive personal information into custom scripts or gameplay unless you are comfortable with that content being saved locally. If you modify the README's LLM example or expose named save slots, add explicit consent for remote API calls and validate save-slot names before reading or writing files.

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
game_engine.py:260
Finding

Path Traversal in Save and Load Operations

Content
View full analysis

Vulnerability Details

File Location: game_engine.py, lines 260–271
Vulnerability Type: Path traversal and unrestricted filesystem access
Risk Level: Medium

Vulnerable Code

python
def _save_game(self, save_name: str = "default") -> None:
    """保存游戏进度"""
    save_file = os.path.join(self.save_path, f"{save_name}.json")
    with open(save_file, "w", encoding="utf-8") as f:
        json.dump(self.game_state, f, ensure_ascii=False, indent=2)

def _load_game(self, save_name: str = "default") -> None:
    """加载游戏进度"""
    save_file = os.path.join(self.save_path, f"{save_name}.json")
    if os.path.exists(save_file):
        with open(save_file, "r", encoding="utf-8") as f:
            self.game_state = json.load(f)

Technical Analysis

The _save_game and _load_game methods interpolate the caller-controlled save_name value directly into a filesystem path. The code neither restricts the value to a safe filename format nor verifies that the resolved path remains inside self.save_path.

A value containing parent-directory components, such as ../../target, can escape the configured save directory. Depending on platform path semantics, an absolute save_name may also cause os.path.join() to discard the intended base directory.

The forced .json suffix limits the reachable filenames but does not prevent traversal. These methods are nominally private and the current command processor invokes them only with the default value; therefore, direct exploitation requires another integration, extension, or caller to expose attacker-controlled save-slot names.

Attack Path

  1. An application integrates TextAdventureEngine and exposes custom save-slot names to an untrusted user.
  2. The attacker supplies a traversal value such as ../../some/writable/location/target.
  3. _save_game() or _load_game() appends .json and combines the result with self.save_path.
  4. The operating system resolves the .. components, causing acces ...[truncated 1116 chars]
Remediation
View remediation

Remediation Suggestions

  1. Restrict save names to a conservative identifier format, such as ^[A-Za-z0-9_-]+$, and reject empty names, path separators, drive prefixes, absolute paths, and . or .. components.
  2. Resolve both the save directory and candidate file to canonical absolute paths, then verify that the candidate remains beneath the save directory before opening it.
  3. Use pathlib.Path for explicit path handling:
python
import re
from pathlib import Path

def _get_save_file(self, save_name: str) -> Path:
    if not re.fullmatch(r"[A-Za-z0-9_-]+", save_name):
        raise ValueError("Invalid save name")

    base = Path(self.save_path).resolve()
    candidate = (base / f"{save_name}.json").resolve()

    if candidate.parent != base:
        raise ValueError("Save path escapes the save directory")

    return candidate
  1. Use the validated helper in both _save_game() and _load_game().
  2. Treat loaded save data as untrusted. Validate its schema, required keys, field types, string lengths, list sizes, and numeric ranges before assigning it to self.game_state.
  3. Handle missing, malformed, oversized, or incompatible JSON files with controlled error reporting rather than leaving the engine in an invalid state.
  4. If multiple users can run the application, isolate save directories per user and apply restrictive filesystem permissions.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The sample LLM integration sends the current scene, player state, and user action to an external API without any privacy or data-handling warning. In this skill's context, users can provide arbitrary custom story content and free-form actions, so the transmitted data may include sensitive personal information, secrets, or regulated content that the user did not expect to leave the local environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README advertises automatic save/load behavior and multiple save slots but does not warn users that gameplay content may be written to local storage. Users may enter sensitive personal or fictionalized-but-real information into custom scripts or gameplay, which could persist unexpectedly and be accessible later.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documented activation phrases and in-game commands are very generic, including terms like '帮助', '退出', '任务', and free-form '直接输入行动/对话'. In an agent environment, broad triggers can cause accidental invocation during normal conversation, leading to unintended state changes, game resets, or the skill taking over interactions unexpectedly.

Content

No source excerpt is available for this finding.

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
93% confidence
Finding

The trigger examples are very broad, such as starting a game from natural language phrases that overlap with ordinary conversation. In an agent ecosystem, overly generic activation patterns can cause accidental invocation or prompt-routing collisions, leading the skill to hijack unrelated user requests and process arbitrary text as game content.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The in-game commands include generic words like '帮助', '退出', and '重新开始' without any game-session qualifier. These terms are common across many assistants and applications, so an active or misrouted skill could intercept routine user intents, causing denial of expected assistant behavior, unwanted state resets, or confusion about which system is responding.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module description and all user-facing commands/help text are written exclusively in Chinese, and command handling expects Chinese inputs such as '存档', '读档', '状态', and '退出'. This imposes a specific language/locale on users without any opt-in or documented region-specific justification, which matches the policy-violation criterion for language constraints.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

Manifest 将该技能描述为文字冒险游戏生成与互动系统,未提及任何持久化或文件管理能力。代码在初始化时创建存档目录,并在后续提供本地存档/读档能力,这超出了纯剧情生成与排版的表述范围。

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

_save_game 和 _load_game 会将完整游戏状态写入并读取本地 JSON 文件。技能描述只声明文字游戏生成、自由互动和排版,没有说明会对本地文件系统进行持久化操作。

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.