Back to skill

Security audit

臺北市公車定點車機 Skill

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Taipei bus information skill using public transit data, with some non-blocking cautions around broad triggers, optional scheduled monitoring, and an insecure map example.

Install only if you want Taipei bus lookup features and are comfortable with public transit API requests and local public-data cache files. Treat the cron/reminder examples as opt-in background automation, and review destination channels before enabling them. Do not reuse the map HTML generator with untrusted data until it serializes data safely, for example with JSON.stringify and coordinate validation.

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
examples/example-map.js:24
Finding

Unescaped Bus Data Embedded into Executable JavaScript

Content
View full analysis

Vulnerability Details

File Location: examples/example-map.js, lines 24–35 and 90
Vulnerability Type: JavaScript injection in generated HTML
Risk Level: Medium

Vulnerable Code

javascript
function generateMapHTML(busesWithCoords, routeFilter = null) {
  const busMarkers = busesWithCoords
    .filter(b => !routeFilter || b.RouteID === routeFilter)
    .map(b => `{
      id: '${b.BusID}',
      lat: ${b.lat},
      lng: ${b.lng},
      route: '${b.RouteID}',
      status: '${b.CarOnStop === '1' ? '停站' : '行駛中'}',
      direction: '${b.GoBack === '1' ? '去程' : '返程'}',
      updated: '${b.DataTime}'
    }`)
    .join(',\n');

The resulting text is inserted directly into an inline script:

javascript
const busData = [${busMarkers}];

Technical Analysis

generateMapHTML() constructs JavaScript source by interpolating properties from busesWithCoords directly into quoted string literals. Values such as BusID, RouteID, and DataTime are not escaped or validated. Likewise, lat and lng are inserted as executable JavaScript expressions without verification that they are finite numbers.

If an attacker can influence a supplied bus record, a value containing a quote followed by JavaScript syntax can terminate the intended string literal and inject arbitrary script into the generated page. For example, a malicious identifier shaped like:

text
'; attackerCode(); //

would alter the syntax of the generated inline script. This flaw arises from treating data as JavaScript source rather than serializing it as data.

The current example does not export or write the generator by itself, which limits immediate exposure. However, it is explicitly presented as implementation guidance for generating an interactive map and is designed to consume records derived from external transit data. Applications that reuse this function and open or serve its output would expose the injection path.

Attack Path

  1. An attacker compromise ...[truncated 1443 chars]
Remediation
View remediation

Remediation Suggestions

  1. Construct ordinary JavaScript objects and serialize the complete array with JSON.stringify() instead of manually creating JavaScript source:
javascript
const busData = busesWithCoords
  .filter(b => !routeFilter || b.RouteID === routeFilter)
  .map(b => ({
    id: String(b.BusID),
    lat: Number(b.lat),
    lng: Number(b.lng),
    route: String(b.RouteID),
    status: b.CarOnStop === '1' ? 'stopped' : 'moving',
    direction: b.GoBack === '1' ? 'outbound' : 'inbound',
    updated: String(b.DataTime)
  }));

const serialized = JSON.stringify(busData)
  .replace(/</g, '\\u003c')
  .replace(/\u2028/g, '\\u2028')
  .replace(/\u2029/g, '\\u2029');
  1. Validate coordinates before serialization:
javascript
if (!Number.isFinite(record.lat) || !Number.isFinite(record.lng)) {
  return false;
}

Also enforce valid geographic ranges for latitude and longitude.

  1. Prefer embedding serialized data in a non-executable block:
html
<script id="bus-data" type="application/json">...</script>

Then parse it with:

javascript
const busData = JSON.parse(
  document.getElementById('bus-data').textContent
);

The serialized JSON must still escape < to prevent an injected </script> sequence from ending the element.

  1. Avoid inline scripts and event handlers such as onclick. Move page logic into a static script file and attach event listeners programmatically.

  2. Deploy a restrictive Content Security Policy that disallows arbitrary inline scripts and limits script sources to the application and the explicitly required mapping provider.

  3. Add regression tests using values containing quotes, backslashes, newlines, </script>, U+2028/U+2029, and JavaScript fragments. Verify that these values remain inert data in the generated document.

  4. Treat all remotely retrieved transit records as untrusted, even when they normally originate from a government endpoint.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (44)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 228)May include surrounding context.

md
- `docs/index.html` — 完整文件網站

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.en.html (reported line 16)May include surrounding context.

html
</head>
<body>

  <!-- Header -->
  <header class="site-header">
    <a href="index.en.html" class="header-brand">
      <span class="header-logo">🚌</span>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.en.html (reported line 174)May include surrounding context.

html
</div>
        </section>

        <!-- ══════════════════════════════════════
             3. Quick Start
        ══════════════════════════════════════ -->
        <section class="section" id="quickstart">

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.en.html (reported line 299)May include surrounding context.

html
</div>
        </section>

        <!-- ══════════════════════════════════════
             5. Data Sources
        ══════════════════════════════════════ -->
        <section class="section" id="data-sources">

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.en.html (reported line 1085)May include surrounding context.

html
</div>
        </section>

        <!-- ══════════════════════════════════════
             8. Use Cases
        ══════════════════════════════════════ -->
        <section class="section" id="use-cases">

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.html (reported line 16)May include surrounding context.

html
</head>
<body>

  <!-- Header -->
  <header class="site-header">
    <a href="index.html" class="header-brand">
      <span class="header-logo">🚌</span>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.html (reported line 304)May include surrounding context.

html
</div>
        </section>

        <!-- ══════════════════════════════════════
             5. 資料來源
        ══════════════════════════════════════ -->
        <section class="section" id="data-sources">

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.html (reported line 687)May include surrounding context.

html
</div>
            </div>

            <!-- getStopCoords -->
            <div class="function-card">
              <div class="function-card-header">
                <div>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.html (reported line 728)May include surrounding context.

html
</div>
            </div>

            <!-- searchStops -->
            <div class="function-card">
              <div class="function-card-header">
                <div>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.html (reported line 859)May include surrounding context.

html
</div>
            </div>

            <!-- searchRoutes -->
            <div class="function-card">
              <div class="function-card-header">
                <div>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.html (reported line 935)May include surrounding context.

html
</div>
            </div>

            <!-- etaBySequence -->
            <div class="function-card">
              <div class="function-card-header">
                <div>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.html (reported line 1017)May include surrounding context.

html
</div>

          <!-- ── ETA 精度三級系統 ── -->
          <h3 style="font-size:16px;font-weight:700;margin:40px 0 16px;padding-bottom:8px;border-bottom:1px solid var(--border);color:var(--text-primary);">
            ⏱️ ETA 精度三級系統
          </h3>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.html (reported line 1138)May include surrounding context.

html
</div>
            </div>

            <!-- 範例 3 -->
            <div class="example-card">
              <div class="example-header">
                <div class="example-number">3</div>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.html (reported line 1200)May include surrounding context.

html
</div>
            </div>

            <!-- 範例 5 -->
            <div class="example-card">
              <div class="example-header">
                <div class="example-number">5</div>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.zh-CN.html (reported line 16)May include surrounding context.

html
</head>
<body>

  <!-- Header -->
  <header class="site-header">
    <a href="index.zh-CN.html" class="header-brand">
      <span class="header-logo">🚌</span>

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.zh-CN.html (reported line 296)May include surrounding context.

html
</div>
        </section>

        <!-- ══════════════════════════════════════
             5. 数据来源
        ══════════════════════════════════════ -->
        <section class="section" id="data-sources">

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · docs/index.zh-CN.html (reported line 1096)May include surrounding context.

html
</div>
        </section>

        <!-- ══════════════════════════════════════
             8. 使用场景
        ══════════════════════════════════════ -->
        <section class="section" id="use-cases">

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The entire instruction file is written as mandatory operating guidance in Traditional Chinese and provides response templates only in that language, with no indication that the agent should adapt to the user's preferred language. This can violate language/locale policy when users have not opted into Chinese or when the skill is used in multilingual contexts.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger condition 'when the user asks about bus-related information' is broad enough that the skill may activate for loosely related transit queries without clear boundaries, causing inappropriate tool use or over-application of this skill. In an agent setting, ambiguous routing can lead to wrong data retrieval, confusion between PTX and internal IDs, and unintended actions such as monitoring or messaging workflows being suggested in contexts the user did not intend.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger examples include broad, conversational phrases such as asking where the bus is or whether it is arriving soon. In an agent environment, these generic utterances can cause unintended invocation during normal conversation, leading the skill to activate when the user did not explicitly intend to use it.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger list is excessively broad and includes very common generic phrases such as '公車' and '公車搜尋', making accidental invocation likely in normal conversation. This can cause unintended skill activation, leading to confusing behavior, unexpected data access/network calls, and poor user control over when the skill runs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
77% confidence
Finding

此檔案全文以繁體中文撰寫,且未說明這是僅限臺北市使用者的語言政策,也未提供其他語言版本或使用者可選擇語言的說明。依規則,當技能強制特定語言而沒有使用者 opt-in 或明確合理化時,屬於自然語言政策風險。

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documented trigger list includes broad natural-language phrases such as 'bus ETA', 'bus route', and mixed-language everyday bus-related terms that could cause the skill to activate on benign conversation not intended to invoke it. In an agent ecosystem, overbroad triggers can lead to unintended tool use, unnecessary network access, and leakage of user context into external API queries.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation explicitly states that mentioning listed keywords will activate the skill, and several triggers are broad everyday phrases such as '等公車', '公車路線', or 'Taipei bus'. In an agent ecosystem, overly broad trigger phrases can cause unintended invocation from normal conversation, which may lead to unnecessary tool use, incorrect routing, or unintended access to external data sources.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation explicitly states the skill activates when the agent merely 'mentions the following keywords,' which implies passive keyword matching instead of explicit user intent. In an agent environment, this can cause accidental tool invocation during ordinary conversation, leading to unnecessary external requests, unintended monitoring behavior, or confusing agent actions.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.