Back to skill

Security audit

经期管理 / Period Tracker

Security checks for vulnerabilities and agentic risk

Overview

This period-tracking skill mostly does what it claims, but it handles very sensitive health data while adding cron reminders and self-update behavior with weak disclosure and safety controls.

Install only if you are comfortable with a local plaintext reproductive-health log, cron-based reminders, and a skill-managed update command. Before using reminders or exports, check file permissions on the data directory, avoid installing the skill in paths with spaces or shell characters, and prefer platform-managed updates over the built-in update action.

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

Warning
Location
scripts/period_tracker.py:53
Finding
Sensitive reproductive-health data is stored without restrictive file permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/period_tracker.py`, lines 53-64 **Vulnerability Type**: Insecure local storage permissions for sensitive health data **Risk Level**: Medium ### Vulnerable Code ```python def load_data() -> dict: DATA_PATH.parent.mkdir(parents=True, exist_ok=True) if not DATA_PATH.exists(): empty = {"version": "1.1", "periods": [], "settings": {"avg_cycle": 28, "avg_duration": 5}} DATA_PATH.write_text(json.dumps(empty, ensure_ascii=False, indent=2)) return empty return json.loads(DATA_PATH.read_text()) def save_data(data: dict): DATA_PATH.parent.mkdir(parents=True, exist_ok=True) DATA_PATH.write_text(json.dumps(data, ensure_ascii=False, indent=2)) ``` ### Technical Analysis The application stores menstrual dates, symptoms, pain levels, mood, flow information, and free-form notes in a plaintext JSON file under the user's home directory. The directory and file are created without explicitly specifying or enforcing restrictive permissions. `Path.write_text()` creates a file using operating-system defaults modified by the process umask. On a system with a permissive umask, the resulting file may be readable by other local users. Existing files with overly broad permissions are also overwritten without correcting their permissions. This is particularly sensitive because the stored information constitutes reproductive and health-related data. Although local plaintext storage is consistent with the documented design, relying only on ambient umask settings does not provide a dependable confidentiality boundary. ### Attack Path 1. A user runs the tracker and records menstrual dates, symptoms, mood information, or notes. 2. The application creates `~/.openclaw/workspace/period_tracker/data.json` with permissions derived from the current process umask. 3. On a permissively configured multi-user system, the file or its parent directories allow another local account to access i ...[truncated 675 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the data directory with owner-only permissions: ```python DATA_PATH.parent.mkdir(parents=True, exist_ok=True, mode=0o700) DATA_PATH.parent.chmod(0o700) ``` 2. Create data files with mode `0600` rather than relying on the process umask. 3. Correct the permissions of existing files before reading or writing them: ```python if DATA_PATH.exists(): DATA_PATH.chmod(0o600) ``` 4. Use an atomic write procedure: - Create a temporary file in the same protected directory. - Open it with `os.open()` using `O_CREAT | O_EXCL` and mode `0600`. - Write and flush the JSON data. - Replace the destination with `os.replace()`. 5. Document that the file contains sensitive health information and provide a secure deletion option. 6. Consider optional application-level encryption if the threat model includes filesystem compromise or shared device access. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/setup_reminder.py:65
Finding
Unquoted Skill path is embedded in persistent cron commands<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup_reminder.py`, lines 65-84; repeated at lines 96-110 **Vulnerability Type**: Shell command injection through an unquoted cron command path **Risk Level**: Medium ### Vulnerable Code ```python # cron format: minute hour day month * cron_line = ( f"{minute} {hour} {remind_date.day} {remind_date.month} * " f'python3 {TRACKER_SCRIPT} today {CRON_TAG} type={reminder_type} days_before={days_before}' ) # Read existing crontab result = subprocess.run(["crontab", "-l"], capture_output=True, text=True) existing = result.stdout if result.returncode == 0 else "" # Remove an older reminder of the same type lines = [l for l in existing.splitlines() if CRON_TAG not in l or f"type={reminder_type}" not in l] lines.append(cron_line) new_crontab = "\n".join(lines) + "\n" proc = subprocess.run(["crontab", "-"], input=new_crontab, text=True, capture_output=True) ``` The same construction is used for daily reports: ```python cron_line = ( f"{minute} {hour} * * * " f'python3 {TRACKER_SCRIPT} today {CRON_TAG} type=daily_report' ) result = subprocess.run(["crontab", "-l"], capture_output=True, text=True) existing = result.stdout if result.returncode == 0 else "" lines = [l for l in existing.splitlines() if CRON_TAG not in l or "type=daily_report" not in l] lines.append(cron_line) new_crontab = "\n".join(lines) + "\n" proc = subprocess.run(["crontab", "-"], input=new_crontab, text=True, capture_output=True) ``` ### Technical Analysis Cron executes command fields through a shell. `TRACKER_SCRIPT`, which is derived from the Skill's installation path, is interpolated directly into the cron entry without shell-safe quoting. An installation path containing whitespace will cause the reminder command to be parsed incorrectly. More importantly, shell metacharacters in the path can alter the command interpreted ...[truncated 1947 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Quote every shell-interpreted cron argument with `shlex.quote()`. 2. Use the absolute path from `sys.executable` instead of the generic `python3` command. 3. Quote both the interpreter path and tracker script path: ```python import shlex python_path = shlex.quote(str(Path(sys.executable).resolve())) tracker_path = shlex.quote(str(TRACKER_SCRIPT.resolve())) cron_line = ( f"{minute} {hour} {remind_date.day} {remind_date.month} * " f"{python_path} {tracker_path} today " f"{CRON_TAG} type={reminder_type} days_before={days_before}" ) ``` 4. Apply the same correction to daily-report cron entries. 5. Validate that generated paths do not contain newline or carriage-return characters before writing crontab content. 6. Consider using a small fixed-path wrapper script with owner-only write permissions, or a scheduler interface that does not require constructing shell command strings. 7. Display the exact cron entry and require explicit confirmation before installation when operating outside a trusted Skill directory. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (34)

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
If the skill modifies crontab or other scheduling state while presenting itself mainly as a natural-language health tracker, it introduces undeclared persistence and system-side effects. Persistence mechanisms are sensitive because they survive the immediate interaction and can execute later without the user understanding what was installed or changed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
If the skill modifies crontab or other scheduling state while presenting itself mainly as a natural-language health tracker, it introduces undeclared persistence and system-side effects. Persistence mechanisms are sensitive because they survive the immediate interaction and can execute later without the user understanding what was installed or changed.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
Executing package-management style update commands from within the skill is a strong supply-chain risk and not justified by the stated functionality. If the update source, package index, or local environment is compromised, the skill can be replaced with malicious code while users are interacting with a health app that stores highly sensitive data.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The natural-language setup path claims success but then invokes `remove_reminders(args.type)` instead of only performing setup, creating deceptive behavior and destructive side effects. This is especially risky because users interacting in natural language may unknowingly trigger deletion of reminders while being told setup completed, undermining trust and potentially suppressing expected health notifications.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill documents shell execution, file reads, and file writes but does not declare any explicit tool scope or permissions boundary. In a health-tracking skill that also mentions updates and reminder setup, this absence increases the chance of overprivileged execution and makes it harder for a host platform to constrain file-system and command execution safely.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger list includes broad everyday phrases related to menstruation, fertility, and reminders, which can cause accidental activation during ordinary conversation. In this context, unintended activation is more serious because it may record sensitive health events, reveal reproductive inferences, or launch side-effecting actions like reminders without deliberate intent.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The examples instruct the assistant to automatically act on ambiguous natural-language statements such as '月经来了' or symptom phrases without an explicit confirmation step. In a sensitive health skill, this can create inaccurate records, privacy exposure, and unintended persistent behavior if a phrase is quoted, discussed hypothetically, or overheard.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The description does not clearly warn that reminder setup may alter local scheduler state and that update checks may reach external services. Missing notice about system-affecting actions undermines informed consent and is particularly concerning for a health skill, where users are likely to expect private note-taking rather than persistence or outbound communication.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The privacy section says data is purely local, but the documented self-update feature implies external communication. For a reproductive-health tool handling sensitive personal data, misleading privacy claims are dangerous because users may disclose intimate information under a false assumption that no outside connectivity exists.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
Stating that no data is uploaded to any server while simultaneously documenting update checks creates a material transparency gap about server communication. Even if health records are not transmitted, metadata such as install presence, version, timing, or environment details may still leak from a highly sensitive health-related workflow.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The entire document, including headings, field descriptions, and example values, is written in Chinese with no indication that other languages are supported. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly justified, which is not present here.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The file includes self-update discovery logic beyond the manifest's core period tracking purpose. Extra operational capabilities are risky in a sensitive-data skill because they widen the attack surface and create opportunities for supply-chain abuse unrelated to user-requested health functionality.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"""检查是否有新版本"""
    try:
        # 使用 clawhub 检查最新版本
        result = subprocess.run(
            ["clawhub", "list"],
            capture_output=True, text=True, timeout=10
        )
Confidence
84% confidence
Finding
Although this call only lists available packages, it initiates an external package-management style interaction unrelated to core period tracking. In context, it normalizes supply-chain interaction from a sensitive health skill and supports the broader self-update behavior, increasing exposure to untrusted external metadata and unexpected operational behavior.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The skill stores highly sensitive menstrual, symptom, mood, and note data in plaintext under the user's home directory without any visible disclosure, consent flow, permission hardening, or encryption. Exposure of this file could reveal intimate health information and personal notes, causing significant privacy harm.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
Inspecting cron configuration during normal reporting is unrelated to the core health-report feature and creates unnecessary visibility into the user's environment. In a menstrual tracker, minimizing unrelated system access is especially important because users may not expect a health skill to enumerate scheduler state.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# 检查是否已设置提醒
    try:
        result = subprocess.run(["crontab", "-l"], capture_output=True, text=True)
        has_reminder = "# period-tracker-reminder" in result.stdout
    except:
        has_reminder = False
Confidence
88% confidence
Finding
The skill inspects the user's crontab during a normal 'today' reporting flow, which exceeds the minimum access needed to report menstrual status. Reading scheduler configuration can reveal unrelated jobs and system habits, creating unnecessary privacy and environment-disclosure risk.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The export feature writes sensitive health records to user-specified files with no warning about destination sensitivity, overwriting risk, or downstream exposure. This can lead users to place intimate records in shared, synced, or world-readable locations without realizing the privacy consequences.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
cmd = [sys.executable, str(setup_script), "add", "--days", str(config["days"]), "--hour", str(config["hour"]), "--minute", str(config["minute"])]
        print(f"   提前天数:{config['days']}天")
    
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode == 0:
        print(f"\n✅ 设置完成!")
        print(f"💡 如需取消,运行:python period_tracker.py reminder --cancel")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
import subprocess
    import sys
    setup_script = Path(__file__).parent / "setup_reminder.py"
    result = subprocess.run([sys.executable, str(setup_script), "remove"], capture_output=True, text=True)
    if result.returncode == 0:
        print("✅ 已取消所有经期提醒")
    else:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return
    
    print("⬇️  正在更新...")
    result = subprocess.run(
        ["clawhub", "update", "period-tracker", "--force"],
        capture_output=True, text=True
    )
Confidence
93% confidence
Finding
This code performs an in-band package-style self-update by executing an external tool to replace or modify the skill. For a health-tracking skill handling sensitive menstrual data, bundling update execution expands the trust boundary and can enable supply-chain compromise or unexpected code changes from within normal skill operation.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The file’s user-facing description, command names, prompts, and parsing logic are all written specifically for Chinese input, and the natural-language mode only recognizes Chinese phrases such as “每天”, “经期”, and “排卵”. This effectively forces a specific language/locale without any opt-in or documented justification, which matches the language/locale policy violation criteria.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def get_next_period_date() -> str:
    """调用 period_tracker 获取下次经期日期"""
    try:
        result = subprocess.run(
            [sys.executable, str(TRACKER_SCRIPT), "predict"],
            capture_output=True, text=True
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def list_reminders():
    """列出当前经期提醒 cron 任务"""
    try:
        result = subprocess.run(["crontab", "-l"], capture_output=True, text=True)
        lines = [l for l in result.stdout.splitlines() if CRON_TAG in l]
        if lines:
            print("📋 当前经期提醒:")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def list_reminders():
    """列出当前经期提醒 cron 任务"""
    try:
        result = subprocess.run(["crontab", "-l"], capture_output=True, text=True)
        lines = [l for l in result.stdout.splitlines() if CRON_TAG in l]
        if lines:
            print("📋 当前经期提醒:")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.