T09 · Insecure Skill Coding Practices
- Location
scripts/monitor_price.py:14- Finding
Predictable Shared Temporary Paths Permit Symlink Attacks and State Tampering
- Content
View full analysis
Vulnerability Details
File Location:
scripts/monitor_price.py, lines 14-44
Vulnerability Type: Unsafe temporary-file handling
Risk Level: MediumVulnerable Code
python # 数据文件路径 DB_FILE = os.environ.get("PRICE_DB_FILE", "/tmp/price_monitor_db.json") SCREENSHOT_DIR = os.environ.get("PRICE_SCREENSHOT_DIR", "/tmp/price_screenshots")python def _ensure_directories(self): """确保数据目录存在""" try: self.screenshot_dir.mkdir(parents=True, exist_ok=True) except Exception as e: print(f"⚠️ 创建截图目录失败: {e}")python def save_data(self): """保存价格数据库""" try: with open(self.db_file, 'w', encoding='utf-8') as f: json.dump(self.data, f, indent=2, ensure_ascii=False) except Exception as e: print(f"❌ 保存数据库失败: {e}") return False return TrueTechnical Analysis
The Skill stores its database and screenshot directory under fixed, globally predictable names in the shared
/tmpdirectory. The database is opened directly in truncating write mode without checking whether the destination is a symbolic link or regular file. The implementation also does not securely create the file, validate its ownership, enforce restrictive permissions, or use an atomic replacement operation.On systems where applicable symbolic-link protections are absent, disabled, or bypassed by the execution context, another local user can pre-create
/tmp/price_monitor_db.jsonas a symbolic link. A subsequent database save can follow that link and truncate or overwrite another file writable by the Skill's effective user. Even when operating-system symlink protections block this exact technique, predictable shared storage still permits pre-creation, denial of service, and unauthorized manipulation where filesystem permissions allow it.Directly truncating the database also makes updates non-atomic. Process interruption or concurrent ...[truncated 1902 chars]
- Remediation
View remediation
Remediation Suggestions
- Replace shared fixed
/tmppaths with a private, user-owned state directory, such as$XDG_STATE_HOME/price-monitoror~/.local/state/price-monitor. - Create the state directory with permissions
0700and database files with permissions0600. - Before reading or writing, verify that the destination is a regular file owned by the expected user and reject symbolic links.
- Where supported, securely open files using flags such as
O_NOFOLLOW,O_CREAT, andO_EXCL. - Write JSON to a securely created temporary file in the same directory, flush and synchronize it, and then atomically replace the database using
os.replace(). - Add file locking or another concurrency-control mechanism to prevent simultaneous processes from losing updates or corrupting the database.
- Validate custom paths supplied through
PRICE_DB_FILEandPRICE_SCREENSHOT_DIR, and fail closed when ownership or permission checks do not pass. - Update documentation to recommend execution as an unprivileged user rather than using a hard-coded
/rootinstallation path.
- Replace shared fixed
