Back to skill

Security audit

Voice Reminder

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real outbound-calling helper, but it has unsafe scheduling code and stores or embeds personal call data in ways users should review before installing.

Install only if you understand that it can place outbound calls through a third-party service, includes hardcoded phone numbers and service identifiers, and stores call history locally. The delayed-call feature should be fixed before use because crafted reminder text could execute shell commands under the agent account.

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/schedule_call.py:196
Finding
OS Command Injection Through Scheduled Call Content## Vulnerability Details **File Location**: `scripts/schedule_call.py:196-209` **Vulnerability Type**: OS command injection through unsafe shell command construction **Risk Level**: Critical ### Vulnerable Code ```python def schedule_task(contact: str, phone_content: str, delay_seconds: int, time_desc: str): """Create a scheduled task; phone_content is the message played during the call.""" script_dir = os.path.dirname(__file__) main_script = os.path.join(script_dir, "main.py") python_exe = get_python_executable() if delay_seconds > 0: cmd = f"(sleep {delay_seconds} && {python_exe} {main_script} '{contact}' '{phone_content}' 0) &" subprocess.Popen(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return True else: subprocess.run([python_exe, main_script, contact, phone_content, "0"]) return True ``` ### Technical Analysis The delayed-execution branch constructs a shell command by directly interpolating `phone_content` into a single-quoted argument and then executes that command with `shell=True`. `phone_content` originates from the command supplied by the user. Although parsing removes certain time expressions and digits, it does not reject or escape shell metacharacters such as single quotes, semicolons, parentheses, redirection operators, or comment characters. An attacker can therefore terminate the quoted argument and append arbitrary shell commands. The immediate-call branch correctly uses an argument list, but delayed calls use an unsafe shell string. Suppressing standard output and standard error also makes exploitation and execution failures less visible. ### Attack Path 1. An attacker submits a delayed outbound-call instruction containing a recognized contact and malicious message content. 2. `parse_command()` extracts the attacker-controlled text as `phone_content`. 3. `schedule_task()` i ...[truncated 908 chars]
Remediation
## Remediation Suggestions - Remove `shell=True` and never construct commands through string interpolation. - Perform delayed execution in Python or use a scheduler that accepts an argument array. - Invoke the target script with a fixed argument list: ```python import time def run_delayed_call(contact, phone_content, delay_seconds): time.sleep(delay_seconds) subprocess.run( [python_exe, main_script, contact, phone_content, "0"], check=True, ) ``` - If a detached process is required, create a small Python worker that receives validated arguments without invoking a shell. - Validate message length and allowed characters as defense in depth, but do not rely on filtering as the primary fix. - Log scheduling and execution failures securely rather than discarding both output streams. - Run the Skill under a dedicated, least-privileged operating-system account with restricted filesystem and network access.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/schedule_call.py:212
Finding
Plaintext Exposure and Persistent Storage of Personal Communication Data## Vulnerability Details **File Location**: `scripts/schedule_call.py:15-20, 212-234`; `scripts/main.py:13-18`; `SKILL.md:14-18`; `scheduled_tasks.json:1-213` **Vulnerability Type**: Hardcoded personal data and insecure plaintext data storage **Risk Level**: Medium ### Vulnerable Code Hardcoded contact data appears in the executable source: ```python CONTACTS = { "季天雄": "15345602935", "天雄": "15345602935", "何天龙": "15655170806", "天龙": "15655170806", } ``` Task records containing phone numbers, message contents, and timestamps are persisted without access-control hardening, redaction, or retention controls: ```python def save_task(contact: str, phone: str, full_content: str, phone_content: str, delay_seconds: int, time_desc: str): """Save task to file.""" tasks = [] if os.path.exists(TASKS_FILE): try: with open(TASKS_FILE, 'r', encoding='utf-8') as f: tasks = json.load(f) except: tasks = [] task = { "contact": contact, "phone": phone, "content": full_content, "phone_content": phone_content, "delay_seconds": delay_seconds, "time_desc": time_desc, "created_at": datetime.now().isoformat(), } tasks.append(task) with open(TASKS_FILE, 'w', encoding='utf-8') as f: json.dump(tasks, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis The project embeds real-looking names and phone numbers in its documentation and source files. It also includes `scheduled_tasks.json`, which contains historical recipient numbers, reminder content, and timestamps. New task records are appended indefinitely to the same plaintext JSON file. The file is opened using default process permissions, with no explicit restrictive mode, encryption, field minimization, deletion policy, or maximum retention period. Consequently, any user ...[truncated 1271 chars]
Remediation
## Remediation Suggestions - Remove personal contact records and historical task data from the distributed project. - Store contacts in protected, user-specific configuration rather than source code or documentation. - Avoid retaining phone numbers and full message contents unless they are operationally necessary. - Apply a documented retention period and automatically delete expired task records. - Create storage files with owner-only permissions, such as mode `0600`, in a protected application-data directory rather than the source tree. - Use encryption at rest when task history must be retained, with keys stored separately from the data. - Redact phone numbers and message content from logs, responses, backups, and diagnostics. - Add `scheduled_tasks.json` and other runtime data files to source-control and package exclusion rules. - Replace the broad `except:` clause with specific exception handling and secure error reporting. - Use file locking and atomic replacement to prevent concurrent writes from corrupting the task database.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared purpose is outbound calling, but the documented behavior includes undisclosed external service access, hardcoded contacts and phone numbers, and synthetic task/message dispatch structures not transparently described to the user. This mismatch impairs informed consent and review, and can hide sensitive data transfer or unauthorized calling behavior behind an innocuous description.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
if delay_seconds > 0:
        cmd = f"(sleep {delay_seconds} && {python_exe} {main_script} '{contact}' '{phone_content}' 0) &"
        subprocess.Popen(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        return True
    else:
        subprocess.run([python_exe, main_script, contact, phone_content, "0"])
Confidence
99% confidence
Finding
This duplicate finding points to the same dangerous behavior: `Popen(..., shell=True)` on a command string assembled from input-derived values. Because the skill's purpose is to process natural-language commands, the hostile-input assumption is strong here, and shell execution turns normal reminder text into a potential RCE vector.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
if delay_seconds > 0:
        cmd = f"(sleep {delay_seconds} && {python_exe} {main_script} '{contact}' '{phone_content}' 0) &"
        subprocess.Popen(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        return True
    else:
        subprocess.run([python_exe, main_script, contact, phone_content, "0"])
Confidence
99% confidence
Finding
This duplicate finding points to the same dangerous behavior: `Popen(..., shell=True)` on a command string assembled from input-derived values. Because the skill's purpose is to process natural-language commands, the hostile-input assumption is strong here, and shell execution turns normal reminder text into a potential RCE vector.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill exposes shell execution, file access, and network-capable behavior without declaring any tool scope or permissions boundary. In an agent setting, this undermines least-privilege controls and can allow a seemingly simple calling skill to invoke broader capabilities than users or the platform expect.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger definition is broad enough to match generic phrases like '通知他们', which can cause the agent to invoke a telephony action during ordinary conversation without sufficiently explicit user intent. Because the skill performs outbound communication, over-triggering raises the risk of unintended calls, privacy violations, and abusive notification behavior.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill does not clearly warn users that it will place outbound phone calls and transmit recipient phone numbers and message content to an external API. That lack of transparency is dangerous because it prevents informed consent for high-sensitivity actions involving personal contact data and third-party data sharing.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
This JSON file stores multiple natural-language reminder messages and contact fields entirely in Chinese, including user-facing content such as reminder text and phone message content. Because the file provides no indication that the skill is region-specific or that users can opt into this locale, it appears to enforce a specific language without documented choice, which matches the language/locale policy violation criteria.

Intent-Code Divergence

Medium
Confidence
92% confidence
Finding
The header comment claims the script only needs simple inputs, but the implementation performs a real outbound API call to an external service and then suppresses any failure. That mismatch is dangerous because users or orchestrating agents may treat this as a harmless formatting/dispatch helper when it actually transmits data and triggers an external side effect without transparent confirmation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code sends a phone number and notification content to a third-party endpoint in a fire-and-forget request, while printing a success-like JSON response before knowing whether the call succeeded. This creates a privacy and integrity risk: sensitive contact/message data is disclosed externally, and callers may be misled into believing the notification was sent even if the request failed or was intercepted/misrouted.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The natural-language description and command examples are entirely Chinese and the parser is built around Chinese time expressions and trigger words, effectively constraining use to one language. The file does not offer an opt-in language choice or explicitly document that this is a Chinese-only, locale-specific skill.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The code schedules work by constructing a shell command and launching it with subprocess.Popen(..., shell=True). Although the module docstring explains scheduling behavior, there is no user-facing disclosure at the execution point that a background shell command will be spawned and continue running asynchronously.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if delay_seconds > 0:
        cmd = f"(sleep {delay_seconds} && {python_exe} {main_script} '{contact}' '{phone_content}' 0) &"
        subprocess.Popen(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        return True
    else:
        subprocess.run([python_exe, main_script, contact, phone_content, "0"])
Confidence
98% confidence
Finding
The code builds a shell command with untrusted data (`contact` and especially `phone_content`) and executes it with `shell=True`. Because `phone_content` is derived from user input and only lightly transformed, a crafted value containing shell metacharacters or quotes can break out of the quoted argument and trigger arbitrary command execution under the agent's privileges.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
subprocess.Popen(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        return True
    else:
        subprocess.run([python_exe, main_script, contact, phone_content, "0"])
        return True
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script persistently stores contact names, phone numbers, and message content in a local JSON file without any access controls, minimization, or retention policy. In a skill that handles outbound calls and reminders, this creates a meaningful privacy exposure because sensitive personal data and message history may be readable by other local users, backups, or logs if the host is shared or compromised.

Natural-Language Policy Violations

Low
Confidence
81% confidence
Finding
The natural-language instructions, examples, and usage guidance are entirely in Chinese, which effectively forces a specific language for use and interpretation. The file does not indicate that this is a China-only or Chinese-only skill, nor does it offer users a language option or opt-in.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The module docstring and all user-facing CLI messages are in Chinese, which effectively forces a specific language for interaction without any opt-in or documented locale constraint. Under the stated policy, language-specific behavior should either provide user choice or clearly justify the restriction.

Intent-Code Divergence

Low
Confidence
97% confidence
Finding
The module header says it 'uses an AI model' to extract call-broadcast content, and this function's docstring describes AI-style extraction. However, the actual implementation only strips fixed time words, digits, and connectors with deterministic regex/string operations, with no model invocation or AI component present. This is an active documentation-to-code contradiction, not merely an omitted detail.

Static analysis

No suspicious patterns detected.