Back to skill

Security audit

Item Management

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its local inventory purpose, but it needs review because delete/restore/export features can lose or expose personal inventory data without enough safeguards.

Review this skill before installing if your inventory data is important or private. Keep backups before delete or restore operations, do not restore JSON backups from untrusted sources, treat generated CSV/HTML reports as sensitive files, and be careful with any cloud-backup setup because it may copy personal item details outside your machine.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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)

T01 · Skill Instruction Hijacking

Note
Location
SKILL.md:277
Finding

Mandatory Agent Response Hijacking Through Skill Instructions

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 277-291
Vulnerability Type: Forced modification of Agent responses
Risk Level: Low

Vulnerable Instruction

markdown
## ⚠️ 强制回复规则(必须遵守)

**每次回复用户物品相关内容时,回复末尾必须包含以下两行:**

💡 试试对我说:查看物品统计 / 搜索XX / 备份物品

想备份数据防丢失?直接说「查看物品存储信息」

text

**规则说明:**
- 第一行是**使用提示**,随机换一个有用的命令提示,如:查看所有物品 / 物品统计 / 搜索XX / 备份物品 / 哪些快过期了 / 导出报告
- 第二行是**备份提示**,固定文案:`*想备份数据防丢失?直接说「查看物品存储信息」*`
- 两行都用 Markdown **斜体**(`*...*`),视觉上弱化,不抢主内容
- **没有例外**,无论是添加、查看、统计、搜索、更新、删除,都必须带这两行

Technical Analysis

The Skill declares a mandatory, exception-free rule that alters every item-related response by appending Skill-selected promotional content. This behavior is not required to perform inventory operations and can conflict with user-selected output formats or higher-level instructions requiring concise or machine-readable responses.

The instruction is activated merely by loading and using the Skill. It therefore changes the Agent's response policy for the current session rather than limiting itself to the functional inventory task.

Attack Path

  1. The Agent loads SKILL.md to process an inventory-related request.
  2. The mandatory response rule becomes part of the Agent's active instructions.
  3. The user requests any supported operation, such as listing, updating, or deleting an item.
  4. The Skill directs the Agent to append its prescribed promotional text regardless of the requested output format.
  5. The resulting response is modified beyond the content needed to satisfy the user's request.

Impact Assessment

The issue affects Agent output integrity within sessions where the Skill is active. It can:

  • Violate strict JSON, XML, or other machine-readable response contracts.
  • Add unsolicited content to every inventory-related response.
  • Override user preferences for concise or exact output.
  • Establish a pattern in which Skill-controlled text ...[truncated 179 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove the mandatory and exception-free response rule.
  • Treat usage suggestions as optional presentation guidance rather than binding Agent behavior.
  • Never append suggestions when the user requests an exact or machine-readable format.
  • Limit Skill instructions to behavior necessary for inventory management.
  • Explicitly state that system, developer, user, and output-format requirements take precedence.
  • If suggestions are retained, display them only when contextually useful and requested.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/item_cli.py:555
Finding

Stored HTML and Script Injection in Generated Exports and Reports

Content
View full analysis

Vulnerability Details

File Location: scripts/item_cli.py, lines 555-578 and 686-717
Vulnerability Type: Unescaped user-controlled data in generated HTML
Risk Level: Medium

Vulnerable Code

python
def _html_row(r: dict) -> str:
    exp = r.get("保质期至", "")
    expiry_cls = ""
    expiry_txt = exp
    if _is_expired(exp):
        expiry_cls = "expiry-warn"
        days = (date.today() - date.fromisoformat(exp)).days
        expiry_txt = f"⚠️ 已过期 {days} 天"
    elif _is_expiring_soon(exp):
        expiry_cls = "expiry-warn"
        days = (date.fromisoformat(exp) - date.today()).days
        expiry_txt = f"⏳ 还剩 {days} 天"
    status_cls = {"在用": "status-active", "已用完": "status-consumed", "已丢弃": "status-discarded"}.get(r.get("状态", ""), "")
    tags = "".join(f'<span class="tag">{t.strip()}</span>' for t in r.get("标签", "").split(",") if t.strip())
    return f"""<tr>
      <td><strong>{r['名称']}</strong></td>
      <td>{r['品牌'] or '—'}</td>
      <td>{r['数量']}{r['单位']}</td>
      <td>{'¥' + str(r['单价']) if r['单价'] else '—'}</td>
      <td>{'¥' + str(r['日均成本']) if r['日均成本'] else '—'}</td>
      <td>{r['购入日期'] or '—'}</td>
      <td class="{expiry_cls}">{expiry_txt}</td>
      <td><span class="status {status_cls}">{r.get('状态','—')}</span></td>
      <td>{tags or '—'}</td>
      <td>{r.get('备注','') or '—'}</td>
    </tr>"""
python
def _report_exp_row(it: dict) -> str:
    exp = it.get("expiry_date") or ""
    status = _status_display(it.get("status"))
    status_cls = {"在用": "status-active", "已用完": "status-consumed", "已丢弃": "status-discarded"}.get(status, "")
    try:
        delta = (date.fromisoformat(exp) - date.today()).days
        if delta < 0:
            exp_txt = f'<span class="exp
...[truncated 3460 chars]
Remediation
View remediation

Remediation Suggestions

  • Escape every dynamic value before placing it in HTML:
    python
    from html import escape
    
    safe_name = escape(str(r.get("名称", "")), quote=True)
    safe_brand = escape(str(r.get("品牌", "")), quote=True)
    safe_note = escape(str(r.get("备注", "")), quote=True)
    
  • Apply escaping to names, brands, units, dates, notes, tags, statuses, and fallback values.
  • Prefer a template engine with automatic HTML escaping enabled.
  • Keep trusted template markup separate from untrusted inventory values.
  • Add a restrictive Content Security Policy, such as one that blocks scripts and remote resources, as defense in depth.
  • Add regression tests using payloads containing element delimiters, quotes, event handlers, and script-capable tags.
  • Treat imported backups as untrusted input and validate their types and field lengths before persistence.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/item_cli.py:417
Finding

Spreadsheet Formula Injection in CSV Exports

Content
View full analysis

Vulnerability Details

File Location: scripts/item_cli.py, lines 417-477
Vulnerability Type: CSV formula injection
Risk Level: Medium

Vulnerable Code

python
def _item_to_row(item: dict) -> dict:
    """Convert item dict to flat row dict for export."""
    return {
        "名称": item["name"],
        "品牌": item["brand"] or "",
        "数量": item["quantity"],
        "单位": item["unit"],
        "单价": item["price"] or "",
        "日均成本": f"{_daily_price(item.get('price'), item.get('production_date')):.2f}" if _daily_price(item.get('price'), item.get('production_date')) is not None else "",
        "购入日期": item["production_date"] or "",
        "存放位置": item["location"] or "",
        "开封日期": item["opened_date"] or "",
        "保质期至": item["expiry_date"] or "",
        "保修期至": item["warranty_date"] or "",
        "状态": _status_display(item["status"]),
        "标签": ",".join(item["tags"]) if item["tags"] else "",
        "备注": item["notes"] or "",
        "添加时间": item["created_at"],
    }

def cmd_export(args):
    fmt = (args.format or "csv").lower()
    items = item_db.list_items(sort_by="name")
    if not items:
        print("📦 没有可导出的物品。")
        return

    rows = [_item_to_row(it) for it in items]
    today = datetime.now().strftime("%Y%m%d")

    if fmt == "json":
        content = json.dumps(rows, ensure_ascii=False, indent=2)
        fname = args.out or f"物品架_{today}.json"
    elif fmt == "html":
        fname = args.out or f"物品架_{today}.html"
        content = _build_export_html(rows, today)
    else:
        fname = args.out or f"物品架_{today}.csv"
        import io as io_module
        buf = io_module.StringIO()
        if rows:
            w = csv.DictWriter(buf, fieldnames=rows[0].keys())
            w.writeheader()
            w.writerows(rows)
        content = buf.getvalue()

    os.makedirs(os.path.dirname(fname) or ".", exist_ok=T
...[truncated 2230 chars]
Remediation
View remediation

Remediation Suggestions

  • Sanitize every string cell before CSV serialization.
  • Prefix cells that may be interpreted as formulas with an apostrophe or another spreadsheet-safe neutralization character.
  • Account for leading whitespace, tabs, carriage returns, and line feeds before checking the first effective character.
  • Apply the protection to all user-controlled fields, including names, brands, units, locations, tags, and notes.
  • Keep JSON exports unchanged unless a consumer-specific reason requires similar transformation.
  • Add tests for formula prefixes and whitespace-obfuscated variants.

Example hardening helper:

python
def safe_csv_cell(value):
    if not isinstance(value, str):
        return value
    stripped = value.lstrip(" \t\r\n")
    if stripped.startswith(("=", "+", "-", "@")):
        return "'" + value
    return value

Apply this helper to every value in each row before calling writerows(). For high-assurance environments, document the chosen neutralization strategy and test it against all supported spreadsheet applications.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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 Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill documents capabilities to read environment variables, read files, and write files, including access to user-home data paths and a cloud-backup config file, but it does not declare any explicit tool scope or permission boundaries. That creates an over-privileged or ambiguously privileged design where the runtime may grant broader filesystem access than users expect, increasing risk of unintended data exposure or modification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill supports restore, delete, export, and cloud-upload related behaviors affecting data integrity and privacy, but the documentation does not require explicit safety checks, provenance validation, or prominent warnings before those operations. Restoring from untrusted JSON, exporting sensitive inventory data, or syncing to third-party cloud targets can expose personal information or overwrite local records with little user awareness.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger set includes broad everyday phrases such as '记录一下' and similar natural-language forms, which can cause accidental invocation outside clear item-management intent. Because the skill can perform state-changing actions like add, update, delete, backup, and restore, unintended activation can lead to unwanted data modifications or privacy-relevant disclosure of personal inventory information.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The search/statistics triggers are overly generic, making it easier for unrelated conversation to be routed into the skill without clear user intent. In this context, accidental invocation is more dangerous because responses may reveal personal possession data, locations, prices, or expiration details, which are privacy-sensitive even if no write occurs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

L271 明确规定“输出使用中文”,这是一个语言策略限制,但文档没有提供用户选择其他语言的选项,也未说明该技能仅面向特定中文场景或合规区域。根据规则,这属于强制特定语言而未获用户选择的自然语言政策问题。

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The delete command performs irreversible removal immediately after invocation, with no confirmation prompt, dry-run, or undo capability. In a data-management tool, accidental or coerced invocation can directly cause data loss, and the skill context increases risk because users are managing personal inventory records they may rely on.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Sub-item deletion is also immediate and irreversible, without warning or confirmation. Even though the scope is narrower than deleting a full item, it can still corrupt inventory records and history integrity through accidental execution.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The schema and messages include Chinese-only user-facing text such as the default unit '个' and later error strings like '无效的备份文件格式'. This imposes a specific language/locale in natural-language outputs and stored defaults without user opt-in or justification for a region-specific tool.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

When merge=False, the import path unconditionally deletes all existing history, subitems, and items before restore. If this path is triggered accidentally, with malformed input, or without an external confirmation layer, it can cause irreversible local data loss for the user.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The file uses fixed Chinese status labels and extensive Chinese user-facing strings throughout the CLI, indicating the skill forces a specific language experience. There is no visible option for users to select another language or opt in to this locale constraint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The export command writes item records, including notes, locations, and other personal inventory metadata, to CSV/JSON/HTML files on disk. While exporting is part of the feature's purpose, the implementation provides no advance disclosure that a local file containing potentially sensitive data will be created at the chosen path.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The manifest describes the skill as managing personal item data by recording, organizing, and querying items. This file additionally exposes full backup, restore, and storage-inspection capabilities, including importing entire datasets and revealing database and backup locations, which go beyond the plain-language scope of everyday item management described in the manifest.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The info command discloses precise local database and backup filesystem paths. While this is not a remote exploit by itself, exposing local storage locations can unnecessarily reveal environment details and make follow-on local attacks or privacy leakage easier, especially in shared or untrusted execution contexts.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The manifest describes a personal item-recording and querying skill, but this module inspects environment variables such as OPENCLAW_WORKSPACE and XDG_DATA_HOME to determine storage locations. While used for local persistence, reading environment configuration is not part of the user-facing item-management purpose and introduces capability beyond the core domain behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The backup routine writes a timestamped JSON file containing all items, subitems, and history into the user's workspace. This is a file-write operation involving potentially sensitive personal inventory data, but the code offers no visible notification, prompt, or warning at the point of creation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.