Back to skill

Security audit

收支管理

Security checks for vulnerabilities and agentic risk

Overview

The skill is a local finance tracker that matches its stated purpose, but users should protect the stored files and treat profit reports as estimates.

Use this only if you are comfortable with a Chinese-language finance tool storing plaintext JSON records locally. Keep the finance data directory out of shared folders, source control, and unencrypted backups, consider tightening file permissions, and verify profit or inventory calculations before using them for business decisions.

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/finance.py:14
Finding

Sensitive Financial Data Stored Without Enforced Restrictive Permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/finance.py, lines 14–29 and 40–41
Vulnerability Type: Plaintext sensitive-data storage with insufficient permission enforcement
Risk Level: Medium

Vulnerable Code

python
DATA_DIR = Path.home() / "private_data" / "openclaw" / "workspace" / "data" / "finance"
DATA_DIR.mkdir(parents=True, exist_ok=True)

PERSONAL_EXPENSES = DATA_DIR / "personal_expenses.json"
SHOP_PURCHASES = DATA_DIR / "shop_purchases.json"
SHOP_SALES = DATA_DIR / "shop_sales.json"
SETTINGS = DATA_DIR / "settings.json"

def init_files():
    for f in [PERSONAL_EXPENSES, SHOP_PURCHASES, SHOP_SALES]:
        if not f.exists():
            f.write_text("[]")
    if not SETTINGS.exists():
        SETTINGS.write_text(json.dumps({
            "monthly_budget": 5000,
            "operating_costs": 0,
            "expense_categories": [
                "餐饮", "购物", "交通", "住房", "医疗", "通讯", "娱乐", "教育", "其他"
            ]
        }, ensure_ascii=False, indent=2))

def save_json(path: Path, data):
    path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")

Technical Analysis

The Skill stores personal spending history, budget settings, shop purchases, sales, inventory-related data, costs, and profits as plaintext JSON files in a predictable location. Directory and file creation do not explicitly enforce owner-only permissions.

Actual permissions therefore depend on the runtime environment's existing permissions and process umask. Under a permissive umask or an inadequately protected parent directory, financial files may be readable by other local users or processes. Subsequent calls to write_text() do not correct insecure permissions on existing files.

The fixed location also makes the records straightforward to discover. This is an insecure coding practice involving sensitive local data, although the code does not itself transmit the records or deliberately grant access to another account.

Attac

...[truncated 1442 chars]

Remediation
View remediation

Remediation Suggestions

  1. Create and validate the data directory with owner-only permissions:
python
DATA_DIR.mkdir(parents=True, exist_ok=True, mode=0o700)
os.chmod(DATA_DIR, 0o700)
  1. Create new files atomically with mode 0600, rather than relying on the process umask. For example, use os.open() with O_CREAT | O_EXCL and an explicit mode.

  2. Validate that each destination is a regular file owned by the expected user before reading or writing it. Reject symbolic links and unexpected file types.

  3. Correct permissions on existing data files where appropriate:

python
for path in (PERSONAL_EXPENSES, SHOP_PURCHASES, SHOP_SALES, SETTINGS):
    if path.exists():
        os.chmod(path, 0o600)
  1. Use atomic writes through a securely created temporary file in the same protected directory, followed by os.replace(). Apply mode 0600 to the temporary file.

  2. Where the threat model includes privileged local attackers, filesystem backups, or device theft, consider authenticated encryption with keys managed separately from the stored JSON files.

  3. Document that the files contain sensitive financial data and should not be placed in shared directories, source control, or unencrypted backups.

Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill performs file read/write operations against a private workspace data directory but does not declare any tool scope or allowed-tools restrictions. This creates an authorization and transparency gap: the runtime may grant broader file capabilities than users or reviewers expect, increasing the risk of unintended access to sensitive financial records or future scope creep into other files.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The module description and user-facing interface are entirely in Chinese, and the accepted natural-language date inputs later in the file are also Chinese-only. This imposes a specific language/locale on users without any opt-in or documented justification, which matches the language policy violation criteria.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

L217 的文档字符串声明“计算毛利(先进先出法)”,但 L238 的注释又写“按最近进货价”,且实际实现只是按日期顺序遍历进货并直接用每条进货数量参与成本累加,没有跟踪历史销售消耗,也没有真正维护 FIFO 库存层。该注释/文档会让调用方误以为利润报表基于严格的先进先出核算,实际结果可能明显偏差。

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.