Back to skill

Security audit

express-monitor

Security checks for vulnerabilities and agentic risk

Overview

This courier-tracking skill mostly does what it says, but it mishandles personal delivery data by storing phone numbers in plaintext while claiming encryption and by under-disclosing third-party lookups.

Install only if you are comfortable with tracking numbers being sent to kuaidi100 and phone numbers plus shipment history being stored locally under your OpenClaw workspace. The skill should be revised before broad use to remove unsupported Feishu/automatic-sync claims, stop claiming encryption unless it is implemented, add a delete/unbind command, and protect or minimize stored phone data.

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
express_monitor.py:25
Finding
Phone Numbers Stored in Plaintext Without Explicit Access Controls## Vulnerability Details **File Location**: `express_monitor.py:25-28` **Vulnerability Type**: Plaintext storage of sensitive personal data **Risk Level**: Medium ### Vulnerable Code ```python def save_phones(phones): """保存手机号""" with open(PHONE_FILE, 'w') as f: json.dump(phones, f, ensure_ascii=False, indent=2) ``` The destination is defined as follows: ```python DATA_DIR = os.path.expanduser("~/.openclaw/workspace/data/express") os.makedirs(DATA_DIR, exist_ok=True) PHONE_FILE = os.path.join(DATA_DIR, "phones.json") ``` ### Technical Analysis Bound phone numbers are serialized directly into `~/.openclaw/workspace/data/express/phones.json` as plaintext JSON. The application does not encrypt the data and does not explicitly enforce restrictive permissions on either the data directory or the resulting file. File accessibility therefore depends on the process environment and its effective `umask`. In an environment with permissive defaults, another local account or process with workspace access may be able to read the stored phone numbers. The data may also be exposed through workspace backups, support bundles, or accidental directory disclosure. This behavior contradicts the statement in `SKILL.md` that phone binding information is stored separately in encrypted form. Users may consequently provide personal data under an inaccurate security assumption. ### Attack Path 1. A user invokes the `bind` command with a valid phone number. 2. `bind_phone()` appends the number to the in-memory phone list. 3. `save_phones()` serializes the list into `phones.json` without encryption. 4. A local actor, compromised process, backup reader, or other party with access to the workspace reads or copies the JSON file. 5. The actor obtains every phone number bound through this skill. This attack requires local filesystem access or another mechanism that exposes the workspace; the code does not itself t ...[truncated 525 chars]
Remediation
## Remediation Suggestions 1. Store phone numbers using operating-system-backed credential storage where available. 2. If file storage is required, encrypt the data with authenticated encryption and keep the encryption key outside the data file, preferably in a platform credential manager. 3. Create the data directory with mode `0700` and the phone file with mode `0600`. Do not rely solely on the ambient `umask`. 4. Use atomic writes through a securely created temporary file, set restrictive permissions before adding sensitive content, and then replace the destination file. 5. Minimize retained data and provide a command that lets users remove bound phone numbers. 6. Mask phone numbers when displaying them, such as `138****8000`, unless full disclosure is explicitly necessary. 7. Update `SKILL.md` so its storage claims accurately reflect the implementation, and do not claim encryption until authenticated encryption or secure credential storage is actually implemented. 8. Review existing installations and securely migrate or delete previously created plaintext `phones.json` files.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • 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
Findings (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared behavior does not match the described functionality: it claims automatic phone-based courier retrieval and Feishu syncing, while the described implementation only stores phone numbers and lacks any Feishu integration. This mismatch is dangerous because users may disclose sensitive phone numbers under false assumptions, and undisclosed network access plus local persistence creates privacy and trust risks.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill declares capabilities that imply file access, file persistence, and network use, but it does not explicitly scope or disclose those permissions in the manifest. That weakens least-privilege controls and makes it harder for users or the platform to understand that phone data and courier history may be written locally and sent to external services.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill encourages phone-number binding and recurring courier syncing without a clear privacy warning or explicit explanation of network and storage effects. In this context, the data is personally sensitive and may be transmitted to courier or aggregator services, so insufficient notice can lead to unintended exposure or collection of personal information.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The skill description claims automatic retrieval by bound phone number and Feishu synchronization, but the code only performs manual tracking queries and stores phone numbers/history locally. This mismatch can mislead users about what data is collected, where it is sent, and what functionality is actually implemented, which is a trust and privacy problem in a data-handling skill.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
Tracking numbers are sent to a third-party logistics service without any explicit privacy disclosure or consent mechanism. Shipment identifiers can reveal purchasing activity and delivery status, so transmitting them externally without notice is a real privacy issue in the context of an end-user monitoring skill.

Tainted flow: 'data' from requests.post (line 53, network input) → requests.post (network output)

Medium
Category
Data Flow
Content
}
    
    try:
        resp = requests.post(url, data=data, headers=headers, timeout=10)
        result = resp.json()
        
        if result.get('status') != '200':
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Phone numbers are persisted to a local JSON file under the user's home directory without a clear user-facing disclosure, retention policy, or protection controls. Because phone numbers are personal data, silent storage increases privacy risk, especially on shared systems or environments where workspace files may be backed up or exposed.

Natural-Language Policy Violations

Low
Confidence
71% confidence
Finding
All user-facing instructions and descriptions in the skill file are presented only in Chinese, and the file does not indicate that this language restriction is optional or justified by a region-specific purpose. Per the policy, forcing a specific language without user opt-in can be a natural-language policy issue.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The top-level natural-language description forces a single language/locale presentation without indicating user choice or a justified region-specific constraint. Under the stated policy, language restrictions should be opt-in or clearly documented as region-specific.

Static analysis

No suspicious patterns detected.