Back to skill

Security audit

travel-city-game(旅行游戏副本生成器)

Security checks for vulnerabilities and agentic risk

Overview

This travel-page skill is purpose-aligned overall, but it needs review because external travel data is inserted into auto-opened HTML in unsafe ways and it relies on an unpinned FlyAI dependency.

Review before installing. Use it only if you trust the FlyAI skill/CLI source, avoid feeding private travel plans into pages you may publish, and prefer local-only preview unless you intentionally want a public URL. Generated pages should treat FlyAI product names, images, and links as untrusted until the template escapes text safely and validates URLs.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
assets/template.html:294
Finding
Externally Sourced Travel Data Enables Stored HTML and JavaScript Injection<![CDATA[ ## Vulnerability Details **File Location**: `assets/template.html:294-309, 423-447, 461-468, 560` **Related Data-Handling Instructions**: `SKILL.md:178, 310-313` **Vulnerability Type**: Stored client-side HTML/JavaScript injection **Risk Level**: High ### Vulnerable Code ```javascript var LOADING_STEPS = {{LOADING_STEPS_JSON}}; var NODES_ORIGINAL = {{NODES_JSON}}; var NODES = JSON.parse(JSON.stringify(NODES_ORIGINAL)); ``` ```javascript var stepsHtml = ''; for (var i = 0; i < LOADING_STEPS.length; i++) { stepsHtml += '<div class="loading-step" id="ls' + i + '">' + LOADING_STEPS[i] + '</div>'; } document.getElementById('loadingSteps').innerHTML = stepsHtml; ``` ```javascript if (node.status === 'unlocked') { buttons = '<div class="btn-group"><a class="btn btn-book" href="' + node.jumpUrl + '" target="_blank" onclick="handleBook(' + i + ')">前往预订</a></div>'; } else if (node.status === 'in_progress') { buttons = '<div class="btn-group">' + '<a class="btn btn-book" href="' + node.jumpUrl + '" target="_blank" onclick="handleViewOrder(' + i + ')">查看订单</a>' + '<button class="btn btn-verify" onclick="handleVerify(' + i + ')">确认到店 (模拟核销)</button>' + '</div>'; } html += '<div class="node-card ' + statusClass + '" id="node-card-' + i + '">' + '<img class="node-img" src="' + node.picUrl + '" alt="' + node.title + '" onerror="this.style.background=\'#333\';this.style.height=\'80px\'">' + '<div class="node-body">' + '<span class="node-index">' + (i + 1) + '</span>' + '<span class="node-title">' + node.chapter + ': ' + node.title + '</span>' + '<span class="node-status-tag ' + tagClassMap[node.status] + '">' + statusTextMap[node.status] + '</span>' + '<p class="node-story">"' + node.story + '"</p>' + '<p class="node-meta">📍 ' + node.address + ' &nbsp;|&nbsp; 🎫 ' + node.skuName + '</p>' + buttons + '</div></div>'; container.innerHTML = html; ``` ```javascript for (var i = 0; i < gameState.rewards.length; i++ ...[truncated 3387 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace HTML-string concatenation with safe DOM construction: - Use `document.createElement`. - Insert textual fields with `textContent`. - Set URLs through DOM properties only after validation. - Avoid assigning externally derived strings to `innerHTML`. 2. Serialize embedded JSON with an HTML-safe serializer: - Escape `<` as `\u003c`. - Escape `>` as `\u003e`. - Escape `&` as `\u0026`. - Escape U+2028 and U+2029. - Ensure `</script>` cannot terminate the containing script element. - Prefer embedding data in an `application/json` element and parsing its `textContent`. 3. Apply strict URL validation: - Parse URLs with a standards-compliant URL parser. - Permit only `https:` for remote booking and image resources. - Reject embedded credentials, control characters, malformed hosts, and unexpected ports. - Where feasible, allowlist official FlyAI or Fliggy destination hosts. - Reject `javascript:`, `data:`, `file:`, `blob:`, and other unneeded schemes. 4. Add `rel="noopener noreferrer"` to every external link using `target="_blank"`. 5. Treat every external CLI response as untrusted, even if it is valid JSON. 6. Add a restrictive Content Security Policy that disallows inline event handlers and limits scripts, images, and navigation destinations. Refactoring inline handlers should precede enabling a strict policy. 7. Add security tests containing payloads with quotes, angle brackets, `</script>`, event handlers, malformed URLs, and Unicode separator characters. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:9
Finding
External FlyAI Skill Dependency Is Not Version or Digest Pinned<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:9-14, 36-42` **Vulnerability Type**: Unpinned third-party Skill dependency **Risk Level**: Medium ### Vulnerable Code ```yaml compatibility: requires: skills: - name: flyai install_hint: "Install from https://clawhub.ai/yealexchen/flyai or run: claude skill install flyai" bins: - python3 - node - flyai ``` ```bash flyai --help ``` The installation guidance resolves the dependency by its mutable package name: ```bash claude skill install flyai ``` ### Technical Analysis The project depends on an external `flyai` Skill and CLI but does not specify an immutable version, commit, artifact digest, or checksum. Installation by package name therefore resolves whatever artifact the remote source serves at installation time. The workflow later executes the resulting CLI and trusts its output as input to the generated application. User confirmation before installation reduces the likelihood of silent compromise, but it does not ensure that the installed artifact is the same code that was previously reviewed. A compromised publisher account, registry, distribution endpoint, or mutable release could change the dependency after this Skill has been audited. This risk is amplified by the client-side injection sinks in the generated template because malicious CLI output can be carried into executable HTML. ### Attack Path 1. An attacker compromises the upstream publisher, package distribution account, or hosting endpoint, or causes a malicious mutable release to be served under the expected `flyai` name. 2. A user follows the documented installation command without an immutable version or checksum. 3. The malicious dependency is installed with the privileges available to the Skill environment. 4. The workflow invokes `flyai --help` and later executes FlyAI search commands. 5. The altered dependency can execute arbitrary behavior permitted to the current user or r ...[truncated 880 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the external Skill to an audited immutable version, commit identifier, or cryptographic artifact digest. 2. Publish the expected: - Package publisher identity. - Version number. - Source revision. - SHA-256 or stronger checksum. - Verified installation source. 3. Verify the installed artifact before invoking it, and fail closed if its version or digest differs from the approved value. 4. Review updates explicitly rather than resolving the latest release automatically. 5. Run the dependency with the minimum required privileges: - Restrict filesystem access. - Restrict environment-variable exposure. - Limit network destinations where sandboxing is available. - Apply execution timeouts and output-size limits. 6. Continue treating all dependency output as untrusted and validate it before embedding it into generated content. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill description presents a travel-itinerary generator, but the instructions also include undeclared side effects like starting background services, opening a browser, managing long-lived processes, and optional public deployment. This mismatch is dangerous because users and orchestrators may authorize or trigger the skill under false assumptions, allowing behaviors beyond the expected trust boundary.

Hidden Instructions

High
Category
Prompt Injection
Content
<!-- ⚠️ 【只读模板文件 - READ-ONLY TEMPLATE】⚠️
     此文件是源模板,AI/Copilot 在任何情况下都 **禁止修改** 此文件。
     - 只能"读取"此文件内容,不能"写入"或"编辑"。
     - 输出结果必须写入 outputs/ 目录(如 outputs/city-game-长沙.html)。
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
<!-- ⚠️ 【只读模板文件 - READ-ONLY TEMPLATE】⚠️
     此文件是源模板,AI/Copilot 在任何情况下都 **禁止修改** 此文件。
     - 只能"读取"此文件内容,不能"写入"或"编辑"。
     - 输出结果必须写入 outputs/ 目录(如 outputs/city-game-长沙.html)。
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill invokes shell commands, writes output files, starts a local HTTP server, and can deploy content publicly, yet it declares no explicit tool scope or allowed-tools restrictions. That increases the blast radius if the skill is mis-triggered or later modified, because the agent may exercise filesystem, process, and network capabilities without manifest-level guardrails.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger phrases are broad enough to match ordinary travel-planning requests, causing the skill to activate in situations where the user did not specifically ask for file generation, shell execution, browser launch, or possible publication workflows. Overbroad triggering is risky here because this skill has side effects beyond pure text generation, so accidental invocation can lead to unnecessary command execution and file/network activity.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The skill includes one-command deployment of generated HTML to a public hosting service, which extends well beyond local page generation. Publishing content to the internet can expose user-provided itinerary content, embedded links, and generated narratives to unintended audiences, especially if users do not fully understand that the result becomes publicly accessible.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The deployment instructions encourage uploading the generated HTML to a public URL but do not prominently warn that the result will be internet-accessible. Because the page contains user-selected city context, generated content, and external booking links, users may unknowingly disclose information or create publicly reachable content they assumed would remain local.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module docstring and all user-facing messages are written only in Chinese, which imposes a specific language on users without any opt-in or alternative locale handling. This matches the language/locale policy violation category because the file hard-codes a single language for interaction.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
防止 PID 被系统复用后误杀其他程序。
    """
    try:
        result = subprocess.run(
            ["ps", "-p", str(pid), "-o", "command="],
            capture_output=True, text=True, timeout=3
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Low
Confidence
76% confidence
Finding
The manifest presents the skill as taking a city name and generating a narrative itinerary, with a dependency on flyai, but does not mention handling credentials or requiring environment-based API authentication. The instructions explicitly tell the user to configure FLYAI_API_KEY in the environment so the CLI can authenticate, which introduces credential handling outside the stated end-user purpose.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The HTML document hard-codes `lang="zh-CN"`, and the visible interface text throughout the template is also fixed in Chinese. This creates a locale-specific user experience without offering opt-in, fallback, or documenting that the skill is intentionally region-specific.

Static analysis

No suspicious patterns detected.