Back to skill

Security audit

Fishing Trip Planner

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a legitimate fishing trip planner, but it needs review because it automatically stores sensitive trip history and generates locally opened HTML reports without adequate containment.

Review before installing. Use only non-sensitive API keys, avoid putting secrets in broadly shared shell startup files, do not use --output for existing or sensitive paths, and treat saved reports/history as private location data. Generated HTML reports should not be opened if they could include untrusted or manipulated API/location data until escaping and stricter local file permissions are fixed.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/fishing_planner.py:644
Finding

Stored HTML Injection in Generated Trip Reports

Content
View full analysis
{date[-5:] if len(date)>=10 else date}
{emoji}
{text_day}
{temp_low}° / {temp_high}°
🌬️ {wind_dir} {wind_scale}级 | 💧 {humidity}%
🌧️ {precip}mm
""" ``` ```python route_steps += f"""
{i+1}
{step['instruction']}
{step['road'] or ''} · {step['distance']}km
""" ``` ```python for t in fishing_score["tide_events"]: tide_rows += f""" {t['emoji']} {t['type']} {t['time']} {t['height']}m """ ``` ```python for name, status, desc in fishing_score.get("conditions", []): tag_class = {"宜": "tag-green", "可": "tag-yellow", "差": "tag-red", "禁": "tag-red", "--": "tag-gray"} tag = tag_class.get(status, "tag-gray") condition_rows += f""" {name} {status} {desc} """ ``` Additional unescaped document-level sinks include: ```python 钓鱼行程规划 - {dest_name} ``` ```python
{origin_name} {mode_info['emoji']} {dest_name}
``` ### Technical Analysis The report generator interpolates user-derived and remotely supplied values directly into HTML without applying HTML escaping. Relevant values include: - Formatted origin and destination names returned by the geocoding API - Route ins ...[truncated 2089 chars]
Remediation
View remediation
``` 6. Add regression tests that pass payloads such as the following through every report field and verify that they appear only as encoded text: ```html "> ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fishing_planner.py:54
Finding

Trip History and Reports May Be Created with Excessive Local Read Permissions

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (23)

Tainted flow: 'config' from os.environ.get (line 71, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 160)May include surrounding context.

python
if config["amap_key"]:
        try:
            resp = requests.get(
                f"{AMAP_BASE}/geocode/geo",
                params={"key": config["amap_key"], "address": "北京"},
                timeout=8

Tainted flow: 'config' from os.environ.get (line 71, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 172)May include surrounding context.

python
if config["qweather_key"]:
        try:
            resp = requests.get(
                f"{QWEATHER_GEO}/city/lookup",
                params={"location": "北京", "key": config["qweather_key"]},
                headers={"Authorization": f"Bearer {config['qweather_key']}"},

Tainted flow: 'params' from os.environ.get (line 439, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 344)May include surrounding context.

python
params = {"key": config["amap_key"], "address": address}
    if city:
        params["city"] = city
    resp = requests.get(f"{AMAP_BASE}/geocode/geo", params=params, timeout=10)
    data = resp.json()
    if data.get("status") == "1" and data.get("geocodes"):
        gc = data["geocodes"][0]

Tainted flow: 'params' from os.environ.get (line 360, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 375)May include surrounding context.

python
log(f"不支持的出行方式: {mode}", "ERR")
        return None

    resp = requests.get(url, params=params, timeout=15)
    data = resp.json()
    if data.get("status") == "1" and data.get("route"):
        return data["route"]

Tainted flow: 'params' from os.environ.get (line 364, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 441)May include surrounding context.

python
key = config.get("qweather_key", "")
    params = {"location": location, "key": key} if key else {"location": location}
    try:
        resp = requests.get(f"{QWEATHER_GEO}/city/lookup", params=params, timeout=10)
        data = resp.json()
        if data.get("code") == "200" and data.get("location"):
            loc = data["location"][0]

Tainted flow: 'config' from os.environ.get (line 71, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 455)May include surrounding context.

python
"""7天天气预报."""
    log("获取7天天气预报", "API")
    try:
        resp = requests.get(f"{QWEATHER_BASE}/weather/7d",
                           params={"location": location_id},
                           headers=_qw_headers(config), timeout=10)
        data = resp.json()

Tainted flow: 'config' from os.environ.get (line 71, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 470)May include surrounding context.

python
"""24小时逐小时预报."""
    log("获取逐小时预报", "API")
    try:
        resp = requests.get(f"{QWEATHER_BASE}/weather/24h",
                           params={"location": location_id},
                           headers=_qw_headers(config), timeout=10)
        data = resp.json()

Tainted flow: 'config' from os.environ.get (line 71, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 485)May include surrounding context.

python
"""潮汐数据. date_str: yyyyMMdd"""
    log(f"获取潮汐数据: {tide_station_id} @ {date_str}", "API")
    try:
        resp = requests.get(f"{QWEATHER_BASE}/ocean/tide",
                           params={"location": tide_station_id, "date": date_str},
                           headers=_qw_headers(config), timeout=10)
        data = resp.json()

Tainted flow: 'config' from os.environ.get (line 71, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 500)May include surrounding context.

python
"""钓鱼指数."""
    log("获取钓鱼指数", "API")
    try:
        resp = requests.get(f"{QWEATHER_BASE}/indices/1d",
                           params={"location": location_id, "type": "1"},
                           headers=_qw_headers(config), timeout=10)
        data = resp.json()

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The primary skill description is written in Chinese and does not indicate that other languages are supported or that Chinese is a required locale for a region-specific tool. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill documents and relies on shell execution, filesystem reads/writes, environment/config handling, and outbound network access, but it declares no explicit tool scope or permission boundaries. That creates an authorization gap where an agent may invoke powerful capabilities without clear least-privilege constraints, increasing the chance of unintended command execution, credential exposure, or unsafe file access.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The trigger phrases are broad and overlap with ordinary travel, weather, and fishing-related requests, so the skill may activate in situations the user did not clearly intend. Because the skill can run scripts, access stored config, and make network requests, over-broad activation raises the risk of unnecessary execution and data access from ambiguous prompts.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The 'When to Use' section defines scope in very general terms without operational constraints, allowing the skill to match common requests like weather, route planning, or recalling prior trips. In context, that broad scope is more dangerous because the skill persists API keys and trip history locally and may open historical HTML reports, so accidental invocation can touch sensitive local state.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api_guide.md (reported line 83)May include surrounding context.

7天天气预报

text
GET https://api.qweather.com/v7/weather/7d
  ?location={LocationID}

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api_guide.md (reported line 92)May include surrounding context.

7天天气预报

text
GET https://api.qweather.com/v7/weather/7d
  ?location={LocationID}

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api_guide.md (reported line 101)May include surrounding context.

7天天气预报

text
GET https://api.qweather.com/v7/weather/7d
  ?location={LocationID}

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api_guide.md (reported line 115)May include surrounding context.

7天天气预报

text
GET https://api.qweather.com/v7/weather/7d
  ?location={LocationID}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The guide tells users to place long-lived API keys in shell startup files like ~/.bashrc, which can unintentionally broaden credential exposure through backups, dotfile syncing, shared accounts, screen sharing, or accidental publication. While this is common operational guidance, the lack of warnings or safer alternatives increases the chance that secrets are stored in places with weak lifecycle control.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The guide states that every trip is automatically saved, including complete HTML reports and itinerary metadata, but does not warn users that sensitive location and travel details will persist on disk. For a travel-planning skill, this can expose home locations, destinations, schedules, and habits to other local users, backups, or malware if retention and permissions are not carefully controlled.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file presents its title, description, usage guidance, prompts, logs, and generated HTML in Chinese, indicating a fixed language/locale behavior. Because this is a code file and there is no visible opt-in, fallback, or documentation justifying a China-specific audience, this appears to violate the language/locale policy constraint.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
84% confidence
Finding

The skill transmits user-provided trip locations, dates, and configured API credentials to third-party services (AMap and QWeather). This is expected for functionality, but it is still a real external data transmission/privacy concern because sensitive travel plans and location queries leave the local environment and are stored/processed by external vendors.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 32)May include surrounding context.

python
TRIPS_INDEX = FISHING_HOME / "trips_index.json"

AMAP_BASE = "https://restapi.amap.com/v3"
QWEATHER_BASE = "https://api.qweather.com/v7"
QWEATHER_GEO = "https://geoapi.qweather.com/v2"

MOODS = {

Tainted flow: 'output_path' from os.environ.get (line 1090, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
83% confidence
Finding

The --output argument is written directly to an absolute path without restriction, allowing arbitrary file overwrite with the privileges of the running user. In agent or automated contexts, a caller could clobber sensitive user files such as shell profiles, application configs, or existing HTML/documents, causing data loss or persistence-related abuse.

Content

Scanner excerpt · scripts/fishing_planner.py (reported line 1068)May include surrounding context.

python
if args.output:
        output_path = os.path.abspath(args.output)
        with open(output_path, "w", encoding="utf-8") as f:
            f.write(html)
        log(f"报告已保存: {output_path}", "OK")
    else:

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

All user-facing instructional content in this file is presented only in Chinese, with no indication that users can choose another language or that the locale restriction is intentional and justified. The policy calls for flagging language or locale constraints when they are imposed without user opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.