Back to skill

Security audit

🏃 Coros

Security checks for vulnerabilities and agentic risk

Overview

This COROS skill is a mostly disclosed fitness-account integration, but it needs review because it stores session secrets in plaintext and can modify or delete training schedules.

Install only if you are comfortable giving the skill access to sensitive COROS fitness data and local session storage. Keep demo mode on until configured intentionally, protect config.json as a secret, do not commit or share it, and avoid setting schedule_write.auto_apply=true unless you have reviewed the exact schedule action and accept the risk of unintended update or deletion.

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

T09 · Insecure Skill Coding Practices

Warning
Location
main.py:236
Finding

Authentication Tokens and Session Cookies Are Persisted in Plaintext

Content
View full analysis

Vulnerability Details

File Location: main.py:236-242
Vulnerability Type: Plaintext storage of authentication credentials
Risk Level: Medium

Vulnerable Code:

python
def _save_token(self) -> None:
    """保存 token 到配置文件"""
    config = load_config()
    config["token"] = self.token
    config["user_id"] = self.user_id
    config["saved_cookie"] = self.cookies
    save_config(config)

The destination function at main.py:114-118 writes the resulting configuration without setting restrictive permissions:

python
def save_config(config: Dict) -> None:
    """保存配置文件"""
    with open(CONFIG_FILE, "w", encoding="utf-8") as f:
        json.dump(config, f, indent=2, ensure_ascii=False)

Technical Analysis

After a successful COROS login, the Skill stores the access token, user identifier, and complete authenticated cookie string in config.json. These values are written as unencrypted JSON. The file is opened using the process's default creation permissions, which depend on the ambient umask; the implementation neither enforces owner-only permissions nor checks the permissions of an existing file.

Access tokens and session cookies are bearer credentials. An attacker generally does not need the original account password if a valid token or cookie can be replayed. Although persistence supports the declared token-caching feature, retaining the full cookie and token in a general configuration file exceeds the safest minimum required for session management.

Attack Path

  1. A user runs the Skill in non-demo mode and successfully authenticates to COROS.
  2. _save_token() adds the access token and authenticated cookies to config.json.
  3. The file becomes accessible through permissive local file permissions, backups, filesystem synchronization, diagnostics, or accidental repository publication.
  4. An attacker extracts token or saved_cookie.
  5. The attacker replays the b ...[truncated 769 chars]
Remediation
View remediation

Remediation Suggestions

  1. Store access tokens and session cookies in an operating-system keyring, credential vault, or platform-provided secret manager rather than config.json.
  2. If file-based storage is unavoidable, create a separate credential file atomically with owner-only permissions such as mode 0600.
  3. Validate and repair permissions before reading or updating an existing credential file.
  4. Store only the minimum cookie values required for authentication rather than the complete cookie header.
  5. Avoid retaining both a token and redundant token-bearing cookie unless the COROS API requires both.
  6. Exclude credential files from source control, package uploads, backups, logs, and diagnostic bundles.
  7. Document how users can revoke cached sessions and provide a command to remove locally persisted credentials securely.
  8. Consider using short-lived tokens and refreshing them through an explicit, narrowly scoped authentication flow.

T09 · Insecure Skill Coding Practices

Warning
Location
main.py:1474
Finding

Failed Explicit Schedule Selection Can Fall Back to an Unrelated Record

Content
View full analysis

Vulnerability Details

File Location: main.py:1474-1477
Vulnerability Type: Unsafe destructive-operation target fallback
Risk Level: Medium

Vulnerable Code:

python
target_record = resolve_target_schedule_record(day_records, schedule_cfg)
if not target_record and len(day_records) == 1 and bool(schedule_cfg.get("allow_single_candidate_fallback", True)):
    # 兼容旧调用:只剩一条日程时,允许自动兜底命中,避免上游传参与名称模板差异导致删除失败
    target_record = day_records[0]

Technical Analysis

The schedule update and deletion flow first attempts to locate a record using configured identifiers or descriptive selectors. If those selectors fail but the selected day contains exactly one record, the code replaces the failed match with that record. This behavior is enabled by default because allow_single_candidate_fallback defaults to True.

A failed explicit selector should ordinarily terminate a destructive operation. Overriding that failure changes the meaning of the request: instead of modifying the record identified by the caller, the Skill modifies whichever record happens to be the sole entry on that date. When auto_apply is enabled, this can result in an unintended update or deletion without a fresh confirmation tied to the actual matched record.

Attack Path

  1. A schedule date contains exactly one legitimate training record.
  2. An update or deletion request supplies an incorrect, stale, misspelled, or otherwise non-matching target identifier.
  3. resolve_target_schedule_record() returns no match.
  4. Because there is one record and the fallback defaults to enabled, the Skill selects that unrelated record.
  5. If schedule_write.auto_apply is true, the selected record is sent to the COROS schedule-update endpoint.
  6. The legitimate record is modified or deleted despite not matching the caller's explicit selector.

Impact Assessment

Exploitation can cause unauthorized modification or deletion of a training ...[truncated 439 chars]

Remediation
View remediation

Remediation Suggestions

  1. Change allow_single_candidate_fallback to default to False.
  2. Never apply a fallback when the caller supplied an explicit target selector that failed to match.
  3. Require an exact stable identifier, such as idInPlan combined with the relevant plan identifier, for deletion and update operations.
  4. Before an applied destructive operation, present the resolved record and require confirmation bound to its immutable identifier.
  5. Treat ambiguous, missing, and failed matches as hard errors rather than compatibility conditions.
  6. If legacy compatibility must remain available, restrict it to preview mode and require an explicit opt-in before converting the preview into a write.
  7. Add tests covering stale identifiers, incorrect names, single-record dates, and multiple-record dates to ensure no unintended record is selected.

T09 · Insecure Skill Coding Practices

Warning
Location
main.py:1729
Finding

Update Failure Triggers Non-Transactional Delete-and-Recreate Logic

Content
View full analysis

Vulnerability Details

File Location: main.py:1729-1760
Vulnerability Type: Non-atomic destructive update with no rollback
Risk Level: Medium

Vulnerable Code:

python
# COROS 对 update payload 校验较严格;若直改失败,降级为“删旧建新”
if action == "update" and not ok and target_record and auto_apply:
    print("  ℹ️ 直改失败,尝试删除旧日程后重建新日程...")
    delete_vo = {
        "id": str(target_record.get("idInPlan", "")),
        "planProgramId": str(target_record.get("planProgramId", "")),
        "planId": str(target_record.get("planId", "")),
        "status": 3,
    }
    del_ok = client.update_schedule([], [], [delete_vo], pb_version=pb_version)
    if del_ok:
        add_cfg = {
            "schedule_write": {
                "action": "add",
                "date": date,
                "name": name,
                "duration_seconds": duration_seconds,
                "hr_low": hr_low,
                "hr_high": hr_high,
                "intensity_percent_low": intensity_percent_low,
                "intensity_percent_high": intensity_percent_high,
                "id_in_plan": int(schedule_cfg.get("replace_id_in_plan", id_in_plan + 1) or (id_in_plan + 1)),
                "source_id": source_id,
                "source_url": source_url,
                "auto_apply": True,
            }
        }
        add_res = handle_schedule_write(client, add_cfg, summary_data)
        result["fallback"] = "delete_then_add"
        result["success"] = bool(add_res and add_res.get("success"))
    else:
        result["fallback"] = "delete_then_add_failed"
        result["success"] = False

Technical Analysis

When a direct schedule update fails, the Skill automatically changes strategy from an update to two separate destructive operations: delete the original record and then add a replacement. The original record is removed before the replacement is created and verified.

These operati ...[truncated 1833 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the automatic delete-and-recreate fallback from the update path.
  2. Prefer an API-supported atomic update operation whenever available.
  3. If replacement is unavoidable, create and verify the new record before deleting the original.
  4. If COROS identifiers prevent create-before-delete, require separate explicit user confirmation that clearly states the original record may be lost.
  5. Preserve a complete validated copy of the original entity, program, and version metadata before deletion.
  6. Implement rollback that recreates and verifies the original record if replacement fails.
  7. Distinguish indeterminate network outcomes from confirmed API rejection; do not delete data after a timeout where the status of the initial update is unknown.
  8. Use idempotency controls or operation identifiers where supported to prevent duplicate or conflicting retries.
  9. Add failure-injection tests for token expiration, timeout, validation rejection, and service interruption between deletion and creation.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The top-level description presents the skill as a data retrieval and review tool, but the documented APIs include schedule mutation and training program calculation workflows. This mismatch is dangerous because users or orchestrators may invoke the skill expecting read-only behavior while it is capable of modifying training data, creating a risk of unauthorized or surprising account changes.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill is described as read-only running data retrieval/analysis, but the code includes schedule mutation capabilities via update_schedule/add_schedule and later delete/update flows. This violates the stated scope and creates a confused-deputy risk: a user or platform may grant trust for viewing data while the skill can alter training plans and delete scheduled workouts.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The main execution path invokes handle_schedule_write during normal operation, meaning hidden write logic is reachable even though the advertised capability is only viewing and summarizing running data. Because the function supports add, update, and delete operations based on config, the skill can modify account state without matching user expectations or manifest disclosures.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The README materially expands the skill from passive running-data retrieval into training schedule add/update/delete operations, including examples for deletion and enabling real writes with auto_apply=true. In an agent context, this creates an authority mismatch: users and platforms may expect read-only behavior, but the documented capability can modify training plans and delete entries, risking unauthorized or accidental state changes.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill declares no explicit tool scope or permissions while its documented behavior clearly implies network access plus local credential/cache reads and writes. In an agent environment, missing scope boundaries can let the skill operate with broader-than-expected capabilities, especially when handling login state, cookies, and personal fitness data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The description highlights automatic login and caching but does not give a clear privacy warning about credential handling, cookies/tokens, and retrieval of sensitive fitness data. This weak disclosure can cause users to underestimate the sensitivity of the operation and consent to persistent authentication or personal data access without understanding the risks.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are broad and map to common running-related conversation, which can cause over-activation of the skill without the user clearly intending account access or personal data retrieval. In context, this is more dangerous because the skill performs automatic login and may expose sensitive fitness history or enable schedule-affecting workflows.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest frames the skill as retrieval/analysis, yet the capability list explicitly includes modifying training schedules. That inconsistency undermines informed consent and safe routing, because a read-oriented fitness skill can unexpectedly become a state-changing integration against a user's account.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Create/update/delete schedule operations are not necessary for the stated purpose of viewing and reviewing running data. Unnecessary mutation capabilities expand attack surface and increase the chance of harmful accidental actions, prompt-triggered misuse, or abuse if the skill is invoked in a loosely controlled conversation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The dialogue trigger section lacks activation boundaries, so ordinary discussion about running could invoke the skill unexpectedly. Because the skill can auto-login and access personal activity data, weak trigger discipline increases privacy risk and the chance of unintended network actions.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The example configuration exposes a schedule_write capability that enables modifying training schedules, while the skill metadata and description present the skill as read-oriented data retrieval and summaries. This mismatch can mislead reviewers and users into granting trust or credentials to a skill that may perform write actions, increasing the risk of unauthorized or unexpected state changes if the write path is implemented or later enabled.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill makes authenticated requests carrying account identifiers, tokens, cookies, and detailed fitness data, but there is no visible consent, disclosure, or data-handling notice in the skill flow. While network transmission to the legitimate vendor API is expected for functionality, the lack of explicit disclosure increases privacy and trust risk in an agent-skill context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code persists access tokens, user IDs, and cookies to a local config file in plaintext without warning or protection. Anyone with local file access, backups, or logs containing that file could reuse the session material to access the user's COROS account and data.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code fetches broad activity data and cycling records even though the skill is presented as running-specific. This expands data access beyond the minimum necessary scope, increasing privacy exposure and violating the principle of least privilege for a narrowly-scoped fitness skill.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · main.py (reported line 1137)May include surrounding context.

python
def display_activity_detail(data: Dict) -> None:
    """展示活动详情(对齐活动详情页核心信息)"""
    summary = data.get("summary", {})
    lap_groups = data.get("lapList", [])
    weather = parse_weather(data.get("weather", {}))
    sport_feel_text = parse_sport_feel(data.get("sportFeelInfo", {}))
    comments_count = data.get("newMessageCount", 0)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation shows account identifiers and cookie/token-like fields in config examples without a strong warning that these are sensitive secrets. In practice, users may store real credentials in plaintext config files or accidentally upload them, enabling account takeover, session hijacking, and privacy exposure if the file is leaked.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

L068-L070 的触发示例如“帮我做个跑步复盘”“本周跑量多少”“训练负荷怎么样”缺少明确限定为 COROS/高驰数据查询场景,和日常健身对话高度重叠。文档也未提供负例或更严格的触发范围说明,容易让技能在非目标语境下被调用。

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documented API surface includes write-oriented endpoints such as training program calculate, schedule update, and related mutation flows that exceed the stated data-viewing purpose. Even in documentation, exposing broader mutating capabilities signals that the skill may invoke actions users do not reasonably expect, increasing the risk of misuse or accidental destructive behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The natural-language content is entirely in Chinese, and the trigger list is predominantly Chinese phrases, with no indication that other languages are supported or that language selection is optional. This can constitute a language policy issue when a skill effectively requires a specific language without documented user opt-in or justification.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger list contains many broad, generic phrases such as '运动数据', '数据分析', '训练计划', and '活动详情' that are not uniquely scoped to COROS. This can cause the skill to activate on unrelated user requests, potentially exposing connected fitness account data or causing actions in the wrong context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The Accept-Language header forces a Chinese-first locale preference (zh-CN, zh) for all requests. The file does not offer the user a language/locale choice or explain that the skill is intentionally region-specific, which conflicts with the locale-choice policy.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The skill queries private profile configuration unrelated to the stated purpose of retrieving running data. Accessing private configuration broadens collection of user data without clear need, which is a privacy and scope-control issue even if the data is not directly displayed.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.