Back to skill

Security audit

Mio Companion

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent companion/chat helper, but it silently persists raw conversation content and inferred tasks and can surface them as executable actions without clear user control.

Review this skill carefully before installing. It keeps local plaintext records of recent chat content, habits, and inferred todos, may create tasks from normal conversation without asking first, and may later present those tasks for execution. Use it only if you are comfortable with local behavioral memory and ensure the host requires explicit confirmation before acting on any returned task.

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
index.js:190
Finding
Plaintext Retention of Complete Conversation Content<![CDATA[ ## Vulnerability Details **File Location**: `index.js`, lines 190–203 **Vulnerability Type**: Sensitive data stored in plaintext **Risk Level**: Medium ### Vulnerable Code ```js const logs = readJson(LOG_FILE, []); logs.push({ role, content, timestamp: new Date().toISOString() }); // Only retain the latest 100 entries if (logs.length > 100) { logs.splice(0, logs.length - 100); } writeJson(LOG_FILE, logs); ``` ### Technical Analysis `ChatLearning.log()` writes message roles and complete message contents to `log.json` without encryption, redaction, sensitivity filtering, or an explicit consent check. Conversations may contain personal information, confidential business data, authentication tokens, or other secrets. The count-based limit of 100 entries reduces the amount of active data but does not impose a time-based retention policy. The implementation also does not provide a user-facing deletion mechanism or explicitly create the data directory and files with owner-only permissions. ### Attack Path 1. A user sends a message containing personal, confidential, or credential-like data. 2. `handleSkill()` passes `context.message.content` to `ChatLearning.log()`. 3. `ChatLearning.log()` stores the complete content in `mio-companion-data/log.json`. 4. A local user, process, backup service, or compromised component with access to the workspace reads the plaintext log. 5. The stored information is exposed or used for subsequent attacks. ### Impact Assessment The vulnerability affects the confidentiality of up to 100 recently recorded messages. An attacker does not gain additional application privileges directly, but any process or account that can read the workspace may obtain sensitive conversation content. Copies retained in backups or snapshots may extend the exposure beyond the application's active retention window. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Do not retain complete conversation messages by default. - Require explicit user consent before enabling conversation logging. - Store only the minimum structured information required, such as an explicitly selected preference. - Redact passwords, access tokens, API keys, private keys, and other sensitive patterns before persistence. - Add time-based expiration and a user-accessible mechanism to inspect and delete stored data. - Create the data directory and files with owner-only permissions, such as `0700` for directories and `0600` for files where supported. - Consider encryption at rest using a key stored outside the data directory. - Document precisely what is collected, why it is collected, and how long it is retained. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:113
Finding
Unvalidated Conversation Text Can Become an Executable Task Request<![CDATA[ ## Vulnerability Details **File Location**: `index.js`, lines 113–132, 247–252, and 282–289 **Vulnerability Type**: Unsafe conversion of untrusted conversation content into actionable instructions **Risk Level**: Medium ### Vulnerable Code ```js mineFromText: (text) => { const patterns = [ /(.+)一下/, // "帮我查一下" /(.+)一下/, // "做一下" /(?:需要|要)(.+)/, // "需要处理" /(?:记住|记得)(.+)/, // "记住" /TODO[::]\s*(.+)/, // "TODO: xxx" /待办[::]\s*(.+)/, /(.+?)(吧|呀|哈|哦)/ // 语气词结尾的命令 ]; const todos = []; for (const pattern of patterns) { const match = text.match(pattern); if (match && match[1]) { const todoText = match[1].trim(); if (todoText.length > 2 && todoText.length < 100) { todos.push(todoText); } } } return todos; } ``` ```js if (typeof input === 'string') { const minedTodos = Todos.mineFromText(input); for (const todo of minedTodos) { Todos.add(todo, 'mining'); } } ``` ```js if (text.includes('执行') || text.includes('做任务')) { const executable = Schedule.getExecutableTasks(); if (executable.length > 0) { return { action: 'execute', data: executable }; } } ``` ### Technical Analysis The task-mining expressions are overly broad. Ordinary conversational statements, quoted text, or attacker-controlled content can match patterns such as `/(?:需要|要)(.+)/` or the pattern accepting text ending in common sentence particles. Matched content is automatically persisted as a todo without user confirmation, task-type validation, or trust-provenance checks. A later execution request returns these inferred todos using the `execute` action. The module does not directly run shell commands or external tools, so exploitation depends on how the surrounding host interprets that action. However, the skill creates an unsafe trust boundary if the host treats ` ...[truncated 1426 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace heuristic extraction with explicit, narrowly defined task syntax. - Show every inferred task to the user and require confirmation before saving it. - Require a second, task-specific confirmation before executing any saved task. - Treat todo text strictly as untrusted data, never as executable instructions. - Map approved tasks to an allowlist of supported operations with typed parameters. - Reject shell syntax, URLs, credentials, and unsupported action types where they are not explicitly required. - Preserve provenance, including the source message, initiating identity, creation method, and confirmation status. - Ensure downstream hosts do not interpret `action: "execute"` as sufficient authorization. - Remove the duplicate regular expression and deduplicate extracted tasks. - Add tests covering quoted commands, forwarded attacker content, ordinary conversational phrases, duplicate matches, and rejected task types. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
index.js:244
Finding
Undefined Method Call Causes Skill-Wide Denial of Service<![CDATA[ ## Vulnerability Details **File Location**: `index.js`, lines 46, 207, and 244 **Vulnerability Type**: Runtime availability failure caused by an inconsistent method name **Risk Level**: Low ### Vulnerable Code The implemented method is named `recordActiveTime`: ```js recordActiveTime: (hour) => { const habits = readJson(HABITS_FILE, { activeHours: {}, preferences: {}, topics: [] }); habits.activeHours[hour] = (habits.activeHours[hour] || 0) + 1; let maxHour = 0, maxCount = 0; for (const [h, c] of Object.entries(habits.activeHours)) { if (c > maxCount) { maxCount = c; maxHour = parseInt(h); } } habits.mostActiveHour = maxHour; writeJson(HABITS_FILE, habits); return habits; }, ``` The call sites invoke a nonexistent method: ```js const hour = new Date().getHours(); Habits.recordActiveHour(hour); ``` ```js const hour = new Date().getHours(); Habits.recordActiveHour(hour); ``` ### Technical Analysis `Habits` defines `recordActiveTime()` but does not define `recordActiveHour()`. Both `handleSkill()` and `ChatLearning.log()` invoke the nonexistent name. JavaScript therefore raises a synchronous `TypeError`. In `handleSkill()`, the failing call occurs before task mining, command processing, heartbeat processing, and normal response generation. Consequently, any ordinary skill invocation can terminate prematurely. When `ChatLearning.log()` is called directly, it writes the conversation log before reaching the failing call, which can leave partial state changes despite reporting an error. ### Attack Path 1. Any user or scheduler invokes `handleSkill()`. 2. The function calls `Habits.recordActiveHour(hour)`. 3. Because the property is undefined, the runtime throws a `TypeError`. 4. The invocation terminates before the requested command is processed. 5. Repeated invocations consistently reproduce the failure, denying normal skill functionality. ### Impact Assessme ...[truncated 360 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Change both call sites to the implemented method name: ```js Habits.recordActiveTime(hour); ``` - Alternatively, rename the implementation and all references consistently. - Add unit tests for every configured trigger and exported method. - Add startup or build-time validation that verifies referenced object methods exist. - Wrap top-level skill processing in controlled error handling so failures return a safe diagnostic rather than terminating unexpectedly. - Avoid partial writes by validating required functions before persistence or by grouping related state changes into an atomic operation where practical. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (14)

Missing User Warnings

High
Confidence
96% confidence
Finding
The skill description states that it records routines, preferences, and chat habits, but provides no warning about what behavioral data is collected, how long it is stored, or how it is used. Because the skill persists this data in local files and combines it with proactive engagement, users may be subject to opaque profiling and privacy-invasive monitoring without informed consent.

Ae1

High
Category
analysis-evasion
Content
- `index.js` - 主技能代码
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ssd 3

High
Confidence
97% confidence
Finding
The skill is explicitly designed to collect and retain habits, preferences, conversations, and mined tasks in natural-language form, which concentrates sensitive behavioral data in plain JSON files. In the context of a 'companion' skill that encourages ongoing personal interaction, this makes inadvertent collection of intimate or identifying information especially likely and increases downstream leakage risk.

Ssd 3

High
Confidence
98% confidence
Finding
The logging path stores raw user messages and the skill later uses stored habits/topics/todos to generate future prompts, creating a feedback loop where sensitive prior disclosures can resurface in later responses. Even without external exfiltration code, this is a real natural-language disclosure channel because private content may be echoed back in contexts where it is inappropriate or visible to others.

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill persistently stores raw conversation content, habits, and behavioral metadata to local JSON files without any notice, consent, minimization, or retention controls beyond a 100-message cap for logs. In a companion/chat skill, users are likely to disclose sensitive personal information, so silent collection materially increases privacy and disclosure risk if the workspace is accessed by other components, users, or backups.

Natural-Language Policy Violations

Medium
Confidence
78% confidence
Finding
All user-facing instructions and the explicit manual trigger phrase are presented only in Chinese, with no indication that users can choose another language. This can constitute a language policy violation when the skill implicitly requires a specific language without opt-in or documented locale restriction.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill advertises proactive messaging, task extraction from conversation, and automatic scheduling/execution, but does not warn users that it may act autonomously based on inferred intent. This is dangerous because users may not expect background actions or outbound messages, increasing the risk of surprise actions, misinterpreted tasks, and erosion of user control.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The manual trigger phrase “陪我聊天” is common natural language and can easily appear in ordinary conversation, causing the skill to activate unintentionally. In a skill that proactively chats, mines tasks, and manages schedules, accidental activation can lead to unwanted data collection or autonomous actions without clear user intent.

Vague Triggers

Medium
Confidence
95% confidence
Finding
Several trigger phrases are generic everyday-language commands such as chatting, checking tasks, and heartbeat/timed checks, which can cause accidental activation or overlap with other skills. In an agent environment, broad triggers increase the chance the skill runs without clear user intent, potentially exposing user data or performing unintended background actions.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
Natural-language descriptions, commands, and responses are limited to Chinese, such as the trigger checks for `陪我聊天`, `查看习惯`, and `查看待办`. Because the file does not offer language selection or explain that the skill is intentionally region-specific, it appears to impose a specific language without user opt-in.

Intent-Code Divergence

Medium
Confidence
87% confidence
Finding
The top-level documentation states the skill will '自动安排时间执行任务' (automatically arrange time to execute tasks). However, the main handler never invokes Schedule.scheduleTask or performs any automatic scheduling logic; it only checks existing schedules and returns executable tasks. This is an intent/documentation contradiction rather than a mere omission because the advertised automatic behavior is not implemented in code.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill mines todos from arbitrary user text and persists them automatically, which can capture sensitive plans, obligations, or personal details the user did not intend to store as structured records. Because this occurs implicitly during normal conversation, it creates a privacy and user-expectation violation and may also lead to unwanted task execution workflows later.

Natural-Language Policy Violations

Low
Confidence
76% confidence
Finding
The natural-language description is presented only in Chinese and indicates a companion behavior style, but there is no indication that users can choose another language or opt into a locale-specific experience. This can violate language/locale policy when the skill implicitly constrains interaction language without documenting that limitation.

Intent-Code Divergence

Low
Confidence
95% confidence
Finding
The inline comment says '如果有习惯数据,使用用户习惯' and the code reads habits.mostActiveHour, implying behavior adapts to learned user habits. In reality, isFreeTime returns only whether the current hour is in a fixed defaultFreeHours array, and userActiveHour is never used. That directly contradicts the stated intent of the comment.

Static analysis

No suspicious patterns detected.