Back to skill

Security audit

Life Capture

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its stated life-log purpose, but it needs review because crafted structured input can make it write Markdown outside the intended daily-notes folder.

Review before installing. Use it only if you are comfortable storing personal life-log data locally under the configured life directory and SQLite database. Until date validation and path containment are added, avoid saving JSON records from untrusted sources, prefer previewing parsed records before writing, and run it in a restricted/test directory if possible.

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/save_entry.py:151
Finding

Path Traversal Enables File Writes Outside the Daily Notes Directory

Content
View full analysis
(str, str): daily_file = root / "daily" / f"{record['date']}.md" ensure_daily_file(daily_file) text = daily_file.read_text(encoding="utf-8") section = SECTION_TITLES[record["type"]] text = ensure_section(text, section) block = build_block(record) marker = f"### {record['id']}\n" if marker in text: start = text.index(marker) next_pos = text.find("\n### ", start + len(marker)) if next_pos == -1: next_pos = len(text) text = text[:start] + block + text[next_pos:] else: header = f"## {section}\n" insert_at = text.index(header) + len(header) text = text[:insert_at] + "\n" + block + text[insert_at:] daily_file.write_text(text, encoding="utf-8") return str(daily_file), block ``` ### Technical Analysis The `date` field is inserted directly into a filesystem path without schema validation, canonicalization, or a containment check: ```python daily_file = root / "daily" / f"{record['date']}.md" ``` The direct-save interface accepts records from standard input or a JSON file, so callers are not restricted to records produced by `parse_entries.py`. A value such as `../../outside` produces a path equivalent to: ```text /daily/../../outside.md ``` The path is then passed to `ensure_daily_file()`, `read_text()`, and `write_text()`. No resolved-path check verifies that the destination remains under `/daily`. The forced `.md` suffix limits the attack to filenames ending in `.md`, but it does not prevent creating or overwriting Markdown files elsewhere within the privileges of the executing user. ### Attack Path 1. An attacker supplies a crafted record through the documented `--stdin-json` o ...[truncated 972 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/save_entry.py:51
Finding

Unescaped Record Fields Permit Markdown Structure Injection

Content
View full analysis
str: tags = " ".join(f"#{t}" for t in record.get("tags", [])) lines = [ f"### {record['id']}", f"- 时间:{format_value(record.get('time'))}", f"- 标签:{tags}", f"- 原始描述:{record.get('raw_text', '')}", f"- 摘要:{record.get('summary', '')}", ] payload = record.get("payload", {}) or {} rtype = record["type"] if rtype == "expense": lines.extend([ f"- 金额:{format_value(payload.get('amount'))}", f"- 币种:{format_value(payload.get('currency'))}", f"- 分类:{format_value(payload.get('category'))}", f"- 子分类:{format_value(payload.get('subcategory'))}", f"- 商家:{format_value(payload.get('merchant'))}", f"- 支付方式:{format_value(payload.get('pay_method'))}", ]) elif rtype == "task": lines.extend([ f"- 状态:{format_value(payload.get('status'))}", f"- 优先级:{format_value(payload.get('priority'))}", f"- 项目:{format_value(payload.get('project'))}", f"- 截止日期:{format_value(payload.get('due_date'))}", f"- 完成时间:{format_value(payload.get('completed_at'))}", ]) elif rtype == "schedule": lines.extend([ f"- 日期:{format_value(payload.get('schedule_date'))}", f"- 开始时间:{format_value(payload.get('start_time'))}", f"- 结束时间:{format_value(payload.get('end_time'))}", f"- 地点:{format_value(payload.get('location'))}", f"- 状态:{format_value(payload.get('status'))}", ]) elif rtype == "idea": lines.extend([ f"- 类型:{format_value(payload.get('idea_type'))}", f"- 状态:{format_value(payload.get('status'))}", f"- 关联任务:{format_value(payload.get('related_task_ ...[truncated 1634 chars]
Remediation
View remediation
Vulnerability Patterns
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • 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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The core parsing/classification portion of the description is accurate: the script accepts text, splits mixed entries, classifies them into several life-log categories, derives tags, parses natural language date/time/amount details, and outputs structured JSON. However, the declared description materially overstates the skill’s behavior in this code chunk. There is no markdown-writing logic at all, and no SQLite synchronization of parsed records; SQLite is only optionally read to determine the next sequence number for generated IDs. The code also supports only four record types—expense, task, schedule, and idea—so reminders are not implemented except perhaps indirectly as todo tasks. Because major declared outputs/storage behaviors are absent from the actual code, this is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The implementation is a persistence layer, not a full note-capture and interpretation skill. It reads JSON input from stdin or a file, expects a non-empty records list, and then saves those records to markdown and SQLite. It does support the storage/sync part of the description for several life-entry types, but key declared behaviors are absent: there is no natural-language parsing, no classification logic, and no tag generation. The supported types are limited to expense, task, schedule, and idea; reminder is not implemented. Also, the markdown path is configurable as /daily rather than explicitly life/daily. Therefore the declared description materially overstates what the code chunk actually does.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/parse_entries.py (reported line 192)May include surrounding context.

python
def apply_first_rule(text: str, rules: List[Dict], default_key: str, default_value: Optional[str]) -> Tuple[Optional[str], List[str]]:
    for rule in rules:
        if re.search(rule['pattern'], text):
            return rule.get(default_key, default_value), rule.get('tags', [])
    return default_value, []

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill instructs the agent to read and write files and execute shell commands, but it declares no explicit tool scope or permissions. This creates an overbroad trust boundary: if auto-selected, the skill could access the filesystem or invoke scripts without any manifest-level restriction, increasing the chance of unintended data modification or command execution.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger language is broad enough to match many normal conversations about organizing information, which can cause the skill to activate in contexts where the user did not clearly intend persistent storage. In this skill, that matters because activation leads to local file/database writes of personal data, so overbroad matching increases the risk of surprise data capture.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill is designed to persist potentially sensitive personal information into markdown files and a local SQLite database, but it does not require a clear user warning or consent flow about storage. This can lead to inadvertent retention of private schedules, expenses, ideas, or task history, which is especially risky on shared machines or synced folders.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The user-visible response template is entirely in Chinese, including headings and field labels, and the document does not state that this is optional or region-specific. This creates a language/locale policy issue because the skill mandates a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This is a markdown file, so SQP-2 applies to omissions in the skill description around behaviors that could affect user data or system integrity. The section explicitly demonstrates a write operation to life/db/life.db, but the surrounding documentation does not warn that running the command will create or modify local persisted data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

All matching rules and hints are written exclusively in Chinese, which effectively constrains the skill to a specific language/locale. There is no accompanying natural-language indication that this is an opt-in Chinese-only configuration or that users can select another locale.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger hints use very common Chinese words such as time references and generic action verbs, which can cause over-broad matching and accidental classification of ordinary text as expenses, tasks, schedules, or ideas. In this skill, that matters because matched content is not only parsed but also written into markdown and synced into SQLite, so false positives can lead to unintended persistence of personal data and incorrect records.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The parser relies on Chinese weekday tokens, Chinese default tags, and Chinese regex hint patterns to classify and extract meaning from input. This imposes a specific language/locale behavior in the skill logic without offering user opt-in or documenting that the skill is intentionally limited to Chinese input.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/process_entry.py (reported line 35)May include surrounding context.

python
parse_cmd.extend(["--today", args.today])
    if args.config:
        parse_cmd.extend(["--config", args.config])
    parsed = subprocess.run(parse_cmd, check=True, capture_output=True, text=True)
    payload = parsed.stdout

    db_path = Path(args.db)

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/process_entry.py (reported line 41)May include surrounding context.

python
db_path = Path(args.db)
    if not db_path.exists():
        init_cmd = [sys.executable, str(script_dir / "init_db.py"), "--db", args.db]
        subprocess.run(init_cmd, check=True)

    save_cmd = [sys.executable, str(script_dir / "save_entry.py"), "--root", args.root, "--db", args.db, "--stdin-json"]
    saved = subprocess.run(save_cmd, input=payload, check=True, capture_output=True, text=True)

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/process_entry.py (reported line 44)May include surrounding context.

python
subprocess.run(init_cmd, check=True)

    save_cmd = [sys.executable, str(script_dir / "save_entry.py"), "--root", args.root, "--db", args.db, "--stdin-json"]
    saved = subprocess.run(save_cmd, input=payload, check=True, capture_output=True, text=True)
    parsed_obj = json.loads(payload)
    saved_obj = json.loads(saved.stdout)
    print(json.dumps({"parsed": parsed_obj["records"], "saved": saved_obj["saved"]}, ensure_ascii=False, indent=2))

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill hard-codes Chinese section titles and later emits Chinese field labels in generated markdown, which imposes a specific language choice on all users. The file does not provide any opt-in, locale selection, or documentation justifying the fixed locale, so this is a language-policy issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The markdown content builder emits multiple Chinese labels such as 时间, 标签, 原始描述, and 摘要 for every saved record. Because the file provides no mechanism for language selection or documented locale constraint, it enforces a fixed language in user-visible output.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code writes user-provided record content to markdown files and updates a SQLite database, but the script contains no docstring, comments, confirmation prompt, or user-facing notice explaining that persistent storage will occur. For a code file, these safety-relevant write operations qualify for a missing-warning finding when there is no visible disclosure in the file.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/save_entry.py (reported line 235)May include surrounding context.

python
def load_payload(args: argparse.Namespace) -> Dict:
    if args.stdin_json:
        return json.load(__import__("sys").stdin)
    if args.input:
        with open(args.input, "r", encoding="utf-8") as f:
            return json.load(f)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The documentation gives project bucket examples only in Chinese (家务 and 健康), which can imply a fixed language/locale expectation for the skill configuration. There is no nearby note indicating that other languages are equally supported or that the locale is intentionally region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The natural-language examples, tags, categories, and summaries are all presented in Chinese, with no indication that language is optional or that the skill is intentionally limited to a Chinese locale. Under SQP-3, forcing a specific language without user opt-in can be a policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This workflow reads user-provided content from stdin or a file and then persists structured results into markdown and SQLite without any confirmation or visibility at this layer. In a life-logging skill that handles personal notes, reminders, expenses, and ideas, silent persistence increases privacy and integrity risk because sensitive data can be recorded or modified based on ambiguous or injected input without an explicit user checkpoint.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.