Back to skill

Security audit

12306 Query

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to do what it says: query China Railway 12306 and write local schedule reports and station-cache data, with no hidden persistence or credential access found.

Before installing, prefer a pinned or verified skill version instead of the unpinned README command. Expect the skill to contact 12306, cache station data locally, and write generated HTML reports; avoid using `--output` on paths you do not intend to overwrite.

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)

T08 · Insecure Dependencies

Warning
Location
README.md:8
Finding
Unpinned Package Execution in the Documented Installation Command<![CDATA[ ## Vulnerability Details **File Location**: `README.md:8` **Vulnerability Type**: Unpinned third-party package and mutable Skill source **Risk Level**: Medium ### Vulnerable Code ```bash npx skills add kirorab/12306-skill ``` ### Technical Analysis The documented installation procedure invokes the `skills` package through `npx` without an exact package version. Depending on the local npm configuration and cache, `npx` can retrieve and execute the latest published version of that package. The referenced Skill is also identified by a mutable repository-style name rather than an immutable commit, signed release, or verified artifact digest. Consequently, the code executed during installation can differ from the code reviewed in this audit. This creates a supply-chain trust boundary involving both the npm package and the mutable Skill source. ### Attack Path 1. An attacker compromises the npm account, package distribution channel, or repository associated with the installation command. 2. The attacker publishes a malicious version of the `skills` package or replaces the mutable Skill content. 3. A user follows the installation command from the README. 4. `npx` downloads and runs the changed package with the privileges of the invoking user. 5. The malicious installer can perform arbitrary actions allowed by that user account. ### Impact Assessment Successful exploitation can provide arbitrary code execution under the installing user's privileges. The resulting scope may include access to user-readable files, environment variables, developer credentials, project files, and network resources. If the command is run by an administrator or inside a privileged automation environment, the impact expands to those privileges. The audited project itself does not demonstrate that the current upstream package is malicious; the risk arises because the installation procedure does not cryptographically or immutably bind execution to the reviewed version. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the installer package to an exact reviewed version, for example: ```bash npx --yes skills@<reviewed-exact-version> add <immutable-skill-reference> ``` 2. Pin the Skill source to an immutable release tag or, preferably, a full commit digest. 3. Publish and verify cryptographic checksums or signatures for installation artifacts. 4. Document the expected package name, version, source repository, and artifact digest. 5. Use a lockfile-backed installation workflow where possible. 6. Run installation with the least-privileged account required and avoid elevated administrative execution. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/query.mjs:192
Finding
Incomplete Encoding of Remote Ticket Data in Generated HTML<![CDATA[ ## Vulnerability Details **File Location**: `scripts/query.mjs:192-214` **Vulnerability Type**: HTML injection through insufficient output encoding **Risk Level**: Low ### Vulnerable Code ```js function seatCell(val) { if (!val || val === '--' || val === '') return '<td class="na">\u2014</td>'; if (val === '无') return '<td class="sold-out">\u65E0</td>'; if (val === '有') return '<td class="available">\u6709</td>'; return `<td class="count">${val}</td>`; } function buildHTML(tickets, from, to, travelDate, filterDesc) { const e = (s) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;'); const fn = e(from.station_name), tn = e(to.station_name); const rows = tickets.map(t => { const swz = t.swz !== '--' ? t.swz : t.tz !== '--' ? t.tz : '--'; const rw = t.rw !== '--' ? t.rw : t.dw !== '--' ? t.dw : '--'; const typeClass = t.trainCode[0]?.toLowerCase() || ''; const buyClass = t.canBuy === 'Y' ? 'yes' : 'no'; return ` <tr> <td class="train-code type-${typeClass}">${e(t.trainCode)}</td> <td class="time"><span class="depart">${e(t.departTime)}</span><span class="arrow">\u2192</span><span class="arrive">${e(t.arriveTime)}</span></td> <td class="duration">${formatDuration(t.duration)}</td> ${seatCell(swz)}${seatCell(t.zy)}${seatCell(t.ze)}${seatCell(rw)}${seatCell(t.yw)}${seatCell(t.yz)}${seatCell(t.wz)} <td class="buy-${buyClass}">${t.canBuy === 'Y' ? '\u53EF\u8D2D' : '\u552E\u7F44'}</td> </tr>`; ``` ### Technical Analysis Ticket fields are parsed from the remote 12306 API response and inserted into a generated HTML document. Several values do not receive context-appropriate encoding: - `seatCell()` inserts `val` directly into an HTML text context. - `formatDuration(t.duration)` can return the original remote value when parsing fails, after which it is inserted directly into HTML. - `typeClass` is derived from a remote train-code character and inserted into an HTML attribut ...[truncated 1736 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Strictly validate every API field before rendering: - Seat values should match an explicit allowlist such as `--`, `无`, `有`, or a bounded numeric format. - Times should match a strict `HH:MM` expression and valid hour/minute ranges. - Durations should match the expected numeric duration format. - Train codes should match the documented train-code syntax. 2. HTML-encode every value inserted into a text context, including seat and duration values. 3. Do not derive CSS classes from unrestricted remote text. Map an allowlisted train type to a fixed class: ```js const allowedTypes = new Set(['g', 'd', 'z', 't', 'k']); const candidate = t.trainCode.slice(0, 1).toLowerCase(); const typeClass = allowedTypes.has(candidate) ? candidate : 'other'; ``` 4. Use a context-aware templating library or DOM construction API instead of manual string interpolation. 5. Add a restrictive Content Security Policy to generated HTML, such as disallowing scripts and limiting network destinations, as defense in depth. 6. Add tests containing markup, quotes, malformed durations, and unexpected API values to verify that output remains inert. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding
The README instructs users to install the skill via `npx skills add kirorab/12306-skill` without pinning a specific version or immutable reference. This creates a supply-chain risk: a later malicious or compromised release of the package/skill could be fetched and executed by users at install time, and README installation commands are especially risky because users often paste them directly into a shell.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes Node.js scripts that query the 12306 official API, which implies network access, but the manifest does not declare any tool scope such as permissions or allowed-tools. This weakens sandboxing and review controls because the runtime capabilities needed by the skill are broader than what the manifest explicitly communicates, making it harder to enforce least privilege or detect unexpected network behavior.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The generated HTML declares `lang="zh-CN"` and renders user-facing labels, status text, and timestamps in Chinese, while the markdown output also uses Chinese headings and labels. This imposes a specific language/locale on all users without opt-in or justification, which matches the language-policy violation criteria.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
This JSON file contains extensive natural-language content in Chinese for station_name and city fields, but provides no indication that the dataset is intentionally limited to Chinese locale or that users can opt into this language setting. For a general-purpose skill asset, this may violate language/locale policy by implicitly forcing one language without user choice or justification.

Static analysis

No suspicious patterns detected.