Back to skill

Security audit

孕期日历提醒 / Pregnancy Calendar Reminders

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but its generator can write outside the chosen output folder if given a crafted filename prefix.

Review before installing. Use only trusted arguments, keep --output-dir in a disposable folder, and avoid custom --prefix values until the script restricts prefixes, verifies paths remain inside the output directory, and refuses accidental overwrites by default.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_pregnancy_calendar.py:585
Finding

User-Controlled Output Prefix Allows Path Traversal and File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_pregnancy_calendar.py, lines 585 and 596–603, with write operations at lines 641–642
Vulnerability Type: Path traversal and arbitrary file overwrite
Risk Level: Medium

Vulnerable Code

python
parser.add_argument("--prefix", default="pregnancy_reminders", help="Output file prefix.")
args = parser.parse_args()

# ...

out_dir = args.output_dir
out_dir.mkdir(parents=True, exist_ok=True)
safe_due = due.isoformat()
base = f"{args.prefix}_due_{safe_due}"
json_path = out_dir / f"{base}.json"
ics_path = out_dir / f"{base}.ics"
outline_path = out_dir / f"{base}_outline.md"
report_path = out_dir / f"{base}_validation.json"

# ...

json_path.write_text(json.dumps(events, ensure_ascii=False, indent=2), encoding="utf-8")
report_path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")

The other generated paths are also passed to writing functions:

python
write_ics(events, ics_path, calendar_name)
write_outline(
    outline_path,
    events,
    windows,
    lmp_input,
    doctor_due,
    lmp,
    due,
    start,
    end,
    calendar_name,
    args.daily_time,
)

Technical Analysis

The --prefix command-line value is concatenated into output path names without validation. Python's pathlib does not guarantee containment when joining an untrusted path component to a trusted directory. A prefix containing ../ components can therefore traverse above --output-dir. An absolute prefix can similarly cause the trusted output directory to be discarded by path composition.

The program then uses Path.write_text() and related output functions without checking whether the destination already exists. These operations truncate and replace existing writable files. There is no filename allowlist, resolved-path containment check, or overwrite confirmation.

The due-date suffix and fixed output extensions constrain the final filenames, but they do not prevent di ...[truncated 1885 chars]

Remediation
View remediation

Remediation Suggestions

  1. Restrict --prefix to a safe filename component. For example, accept only letters, digits, periods, underscores, and hyphens:

    python
    def parse_prefix(value: str) -> str:
        if not re.fullmatch(r"[A-Za-z0-9._-]+", value):
            raise argparse.ArgumentTypeError(
                "Prefix may contain only letters, digits, periods, underscores, and hyphens"
            )
        if value in {".", ".."}:
            raise argparse.ArgumentTypeError("Invalid output prefix")
        return value
    
    parser.add_argument(
        "--prefix",
        type=parse_prefix,
        default="pregnancy_reminders",
        help="Output filename prefix.",
    )
    
  2. Resolve and verify every destination remains beneath the resolved output directory:

    python
    out_dir = args.output_dir.resolve()
    out_dir.mkdir(parents=True, exist_ok=True)
    
    def contained_output(filename: str) -> Path:
        candidate = (out_dir / filename).resolve()
        if candidate.parent != out_dir:
            raise SystemExit(f"Output path escapes output directory: {candidate}")
        return candidate
    
  3. Use contained_output() for all four generated paths.

  4. Refuse to overwrite existing files by default. Add an explicit --force option when replacement is intentional:

    python
    for path in (json_path, ics_path, outline_path, report_path):
        if path.exists() and not args.force:
            raise SystemExit(f"Output file already exists: {path}")
    
  5. For stronger protection against race conditions, create new files using exclusive creation mode ("x") rather than checking and then writing separately.

  6. Add regression tests covering:

    • Prefixes containing ../ and path separators.
    • Absolute prefixes.
    • Existing destination files.
    • Symlinks that resolve outside the output directory.
    • Valid ordinary prefixes.
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill instructs the agent to read reference files and generated validation/output artifacts and to write calendar files, but it does not declare any explicit tool scope or allowed-tools boundary. That means the agent may use file read/write capabilities without a least-privilege contract, increasing the chance of unintended access to other local files or writing to unintended locations if the workflow is modified or user input influences paths.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This Python skill emits calendar names, reminders, validation text, and medical guidance in Chinese, and also fixes the timezone to Asia/Shanghai. The file does not provide any user opt-in, language selection, or justification that the skill is intentionally restricted to a Chinese-speaking/China locale context, which matches the policy's language/locale violation criterion.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.