Back to skill

Security audit

iwatch-swim-tracker

Security checks for vulnerabilities and agentic risk

Overview

This swim-tracking skill is not clearly malicious, but it should be reviewed because it saves personal workout data and has weak date/path validation that can write or read JSON files outside its intended data folder.

Install only if you are comfortable with the skill storing swim and heart-rate history locally. Review or fix the date validation before using it with untrusted screenshots or direct JSON, and be aware that same-day records are overwritten rather than versioned.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/extract_swim_data.py:30
Finding

Path Traversal in Date-Based Record Storage and Lookup

Content
View full analysis
dict: """按日期归档保存,同一天多次训练追加到数组。返回结果字典。""" date_str = data["date"] # YYYY-MM-DD year, month, _ = date_str.split("-") dir_path = DATA_DIR / year / month dir_path.mkdir(parents=True, exist_ok=True) file_path = dir_path / f"{date_str}.json" # 同一天的数据直接覆盖(用户可能重发截图以更正数据) file_path.write_text(json.dumps([data], ensure_ascii=False, indent=2), encoding="utf-8") return { "status": "saved", "file": str(file_path), "date": date_str, "total_distance": data["total_distance"], } def check_date(date_str: str) -> dict: """检查某日期是否已有训练记录。""" year, month, _ = date_str.split("-") file_path = DATA_DIR / year / month / f"{date_str}.json" if file_path.exists(): existing = json.loads(file_path.read_text(encoding="utf-8")) if not isinstance(existing, list): existing = [existing] return { "exists": True, "date": date_str, "sessions": len(existing), "data": existing, } return {"exists": False, "date": date_str} ``` ### Technical Analysis The `date` value is expected to use the `YYYY-MM-DD` format, but the implementation only splits it on hyphens. It does not validate the resulting components, reject path separators or traversal sequences, parse the value as a real calendar date, or verify that the resolved destination remains beneath `DATA_DIR`. Both `year` and `month` are incorporated directly into filesystem paths. The complete untrusted `date_str` is also incorporated into the filename. A value containing directory separators and `..` components can consequently alter the resolved path. The `save()` operation creates attacker-influenced directories ...[truncated 1974 chars]
Remediation
View remediation
str: if not isinstance(value, str): raise ValueError("date must be a string") parsed = datetime.strptime(value, "%Y-%m-%d") canonical = parsed.strftime("%Y-%m-%d") if value != canonical: raise ValueError("date must use canonical YYYY-MM-DD format") return canonical ``` 2. Construct directories only from the parsed date rather than raw substrings: ```python date_str = canonical_date(data["date"]) parsed = datetime.strptime(date_str, "%Y-%m-%d") file_path = DATA_DIR / parsed.strftime("%Y") / parsed.strftime("%m") / f"{date_str}.json" ``` 3. Enforce containment before every read or write: ```python data_root = DATA_DIR.resolve() resolved_path = file_path.resolve() if not resolved_path.is_relative_to(data_root): raise ValueError("resolved path escapes the data directory") ``` 4. Apply the same canonical validation and containment checks to both `save()` and `check_date()`. 5. Reject path separators, NUL characters, traversal components, and non-string date values before filesystem operations. 6. Avoid returning absolute local paths unless callers require them. 7. Add regression tests covering `../`, absolute paths, embedded separators, invalid dates, extra hyphens, Unicode separator-like characters, and symlinks beneath the data directory. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/extract_swim_data.py:24
Finding

Presence-Only Validation Allows Malformed and Poisoned Training Records

Content
View full analysis
list[str]: """校验必填字段,返回缺失字段列表。""" return [f for f in REQUIRED_FIELDS if f not in data or data[f] is None] ``` ### Technical Analysis The validation routine verifies only that required keys exist and are not `None`. It does not enforce the types, formats, ranges, or relationships declared in `SKILL.md` and `references/data_schema.md`. Missing checks include: - Canonical and valid `YYYY-MM-DD` dates. - Valid `HH:MM-HH:MM`, duration, and pace formats. - Numeric types and reasonable ranges for distances, lap counts, durations, calories, pace, and heart rate. - Restriction of stroke names to the documented set. - Verification that stroke distances sum to the total distance. - Verification that lap count multiplied by pool length approximately equals total distance. - Consistency between textual durations or pace values and their numeric equivalents. - Rejection of booleans where Python would otherwise treat them as integers. - Limits on nested object sizes and unexpected fields. Malformed records are persisted and later consumed by `query_history.py`, whose arithmetic assumes numeric values. This can cause runtime exceptions, corrupt trend calculations, or create misleading analysis. The bundled data demonstrates schema inconsistency: one record uses the unsupported stroke key `mixed` rather than documented `medley`, and records use both `calories` and the documented `active_calories`/`total_calories` fields. This is evidence of data-quality drift, not evidence of malicious content. ### Attack Path 1. An attacker submits direct JSON or causes screenshot recognition to produce malformed values. 2. All required keys are included, but one or more values have incorrect types, extreme values, unsuppor ...[truncated 1096 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
scripts/split_screenshot.py:1
Finding

Unpinned Third-Party Dependency Installation Instruction

Content
View full analysis
``` ### Technical Analysis The installation instruction asks users to retrieve `Pillow` without a version constraint, lock file, or package hash. The effective dependency can therefore change over time even when the Skill itself has not changed. Installing the latest package from the configured package index makes builds non-reproducible and exposes users to future compromised releases, account takeover of the package publisher, repository compromise, or incompatible updates. The package name is correctly spelled, and the audited project contains no evidence that the current Pillow package is malicious. The finding concerns unsafe dependency management rather than a confirmed malicious dependency. Image-decoding libraries also process complex, attacker-supplied formats. Unreviewed upgrades can unexpectedly change parser behavior or security properties. ### Attack Path 1. Pillow is absent from the environment. 2. A user follows the source-code instruction and creates a virtual environment. 3. `pip install Pillow` resolves whichever release and artifacts are current on the configured package index. 4. If that release, distribution artifact, publisher account, package source, or index is compromised, attacker-controlled package code may run during installation or import. 5. That code executes with the privileges of the user running `pip` or the image-splitting script. ### Impact Assessment A compromised dependency could execute code with the invoking user's privileges, read or modify files accessible to that user, and access network reso ...[truncated 377 chars]
Remediation
View remediation
Vulnerability Patterns
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

声明的核心能力包括:基于图片/关键词触发、识别 Apple Watch 泳池游泳截图、提取训练数据、保存记录并生成趋势分析报告。实际代码仅是一个后处理/存储脚本:它从命令行接收 JSON,验证字段,按日期写入本地 JSON 文件,并支持通过 --check-date 查询某日已有记录。也就是说,声明中的“识别图片并提取数据”这一主要功能并未在该代码中实现,趋势分析报告、历史对比和个性化建议也未实现。虽然“保存训练记录”与声明部分一致,但整体主功能明显比声明更窄,且包含未声明的日期查询/读取能力,因此存在描述与行为不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

声明描述的是一个以图片识别为入口的完整游泳训练记录技能,核心能力包括:识别截图、提取数据、保存记录、再做趋势分析。而实际代码块只是一个历史查询与统计脚本:它读取本地 JSON 文件,计算总距离、平均配速、平均心率、卡路里、时长,并给出最近若干天趋势和若干周对比。虽然“趋势分析/历史对比”与声明中的后半部分部分一致,但该代码缺少声明中的主要前置能力和触发条件,且其主要行为更像离线历史数据查询工具。因此描述与实际行为存在明显不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

声明描述的是一个完整的游泳训练截图解析与分析技能,包括识别特定来源截图、提取结构化指标、保存记录、做历史趋势分析。实际代码只是一个辅助预处理工具:读取单张图片,按固定百分比裁切成长截图的多个区域并落盘。虽然分段标签包含距离、配速、心率等字段名称,说明其可能服务于后续视觉识别流程,但当前代码本身并不执行这些声明中的核心功能。因此其主要用途与声明存在实质性偏差,应判定为不匹配。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill invokes local Python scripts that can read and write training data, but it does not declare any explicit tool scope or permissions. This weakens least-privilege boundaries and can let the skill access filesystem capabilities beyond what users or the platform may expect, especially because it persists records and queries history.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill stores extracted health-related workout records and overwrites same-day data without clearly warning users. Because swim metrics and heart-rate data are personal health information, undisclosed persistence and replacement behavior can cause privacy harm, unexpected retention, and silent data loss.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This Python file contains its primary docstring entirely in Chinese, which establishes the skill's behavior and usage in a single language. The policy explicitly flags language or locale constraints when the skill does not offer a user choice or document a justified regional limitation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The save function docstring states that multiple training sessions on the same day are appended to an array, implying preservation of prior records. However, the implementation unconditionally writes json.dumps([data], ...) to the date file, replacing any existing contents; the inline comment at L045 also acknowledges overwrite behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This file contains natural-language descriptions, usage examples, and later CLI help text exclusively in Chinese. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which it is not here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The argparse description and option help strings are presented only in Chinese, so users are forced into a single language for core interaction with the skill. The file does not offer an opt-in language choice or explain that the tool is intentionally limited to a Chinese locale.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module docstring explicitly says it splits '即刻游长截图' into segments for vision recognition, and the segment labels are tailored to a specific long screenshot layout with many panels. This differs from the manifest, which claims the skill is for Apple Watch fitness pool-swim record screenshots and structured extraction/trend reporting from those images.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The implementation opens a local image, crops it into predefined regions, writes JPEG files, and returns JSON metadata about the saved segments. It does not perform OCR/vision extraction, save training records, or generate analysis reports as described in the manifest.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The natural-language description, trigger conditions, and reply format are entirely specified in Chinese, including required keyword matching on the Chinese word "游泳" and a Chinese output template. The file does not indicate that users may choose another language or that the locale restriction is intentional and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file contains user-facing schema documentation only in Chinese, including headings, field descriptions, and examples. Under the language/locale policy, forcing a specific language without opt-in or justification can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

Although the command-line usage text is partly in English, the operational descriptions and comments remain Chinese-only and there is no indication that users can choose their preferred language. This can violate a language policy when the skill implicitly requires one locale without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The value "适中" is a Chinese-language label embedded in the file, which implies a fixed locale choice. For all file types, locale-specific language should not be forced unless the skill offers user choice or clearly documents a justified regional constraint.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.