T09 · Insecure Skill Coding Practices
- Location
scripts/express_tracker.py:34- Finding
Shipment Tracking Data Stored Without Explicit Restrictive Permissions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/express_tracker.py, lines 11-12, 34-41, and 164-171
Vulnerability Type: Plaintext sensitive-data storage with process-default permissions
Risk Level: MediumVulnerable Code
python DATA_DIR = os.path.expanduser("~/.qclaw/skills/cn-express-tracker/data") DATA_FILE = os.path.join(DATA_DIR, "express.json")python def load(): os.makedirs(DATA_DIR, exist_ok=True) if os.path.exists(DATA_FILE): return json.load(open(DATA_FILE)) return {"tracking": []} def save(d): with open(DATA_FILE, "w") as f: json.dump(d, f, ensure_ascii=False, indent=2)python existing = [i for i in data["tracking"] if i["number"] == num] if existing: existing[0].update({"carrier": carrier, "last_status": last_s, "last_time": last_t}) save(data) return f"♻️ 更新 {num}({carrier})\n📍 {last_s}" data["tracking"].append({"number": num, "carrier": carrier, "last_status": last_s, "last_time": last_t}) save(data) return f"✅ 已添加\n━━━━━━━━━━━━━━\n📦 {num}\n🏢 {carrier}\n📍 {last_s}"Technical Analysis
The application persists tracking numbers, carrier identifiers, shipment status text, and timestamps in a plaintext JSON file. These values can reveal sensitive logistics information, including package identifiers and recent shipment activity.
The storage directory is created with
os.makedirs()without an explicit owner-only mode, while the data file is created throughopen(..., "w")without an explicit permission mode. Consequently, effective permissions depend on the runtime environment's umask and any pre-existing directory or file permissions. Under a permissive umask, the directory or JSON file may be readable by other local accounts.The implementation also does not verify that an existing file is owned by the expected user, reject sym ...[truncated 1332 chars]
- Remediation
View remediation
Remediation Suggestions
-
Create the storage directory with owner-only permissions and correct permissions on existing directories:
python os.makedirs(DATA_DIR, mode=0o700, exist_ok=True) os.chmod(DATA_DIR, 0o700) -
Create the data file with mode
0600by usingos.open()rather than relying on process-default permissions:python flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC fd = os.open(DATA_FILE, flags, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as f: json.dump(d, f, ensure_ascii=False, indent=2) -
Validate existing storage before reading or writing:
- Confirm that the file is owned by the current user.
- Reject symbolic links using
os.lstat()or platform-supported no-follow flags. - Reject unexpected file types.
- Correct permissions to
0600when safe to do so.
-
Use an atomic write strategy:
- Securely create a temporary file in the same directory with mode
0600. - Write and flush the complete JSON document.
- Optionally call
os.fsync(). - Atomically replace the destination using
os.replace().
- Securely create a temporary file in the same directory with mode
-
Minimize persisted information. Store only fields required for functionality and provide a clear retention or deletion mechanism for shipment data.
-
Update the privacy documentation to state that tracking numbers are sent to Kuaidi100 for lookup and that results are stored locally in plaintext with owner-only access.
-
