T09 · Insecure Skill Coding Practices
- Location
scripts/watchboard.py:27- Finding
Predictable Shared Temporary Cache Permits Symlink Attacks and Cache Poisoning
- Content
View full analysis
bytes: """Fetch URL with local file cache.""" CACHE_DIR.mkdir(parents=True, exist_ok=True) safe_name = re.sub(r'[^\w\-.]', '_', url.replace('https://', '')) cache_file = CACHE_DIR / safe_name if not force and cache_file.exists(): age = time.time() - cache_file.stat().st_mtime if age < CACHE_TTL: return cache_file.read_bytes() req = urllib.request.Request(url, headers={"User-Agent": "OpenClaw-Watchboard/2.0"}) try: with urllib.request.urlopen(req, timeout=30) as resp: data = resp.read() cache_file.write_bytes(data) return data except urllib.error.HTTPError as e: print(json.dumps({"error": f"HTTP {e.code}", "url": url})) sys.exit(1) except Exception as e: print(json.dumps({"error": str(e), "url": url})) sys.exit(1) ``` ### Technical Analysis The application stores cached network responses in the fixed, predictable directory `/tmp/watchboard-cache`. It creates that directory without setting or validating restrictive permissions and does not verify that the directory is owned by the current user. Cache filenames are deterministic because they are derived from fixed, publicly documented API URLs. Although invalid filename characters are replaced, this sanitization does not address filesystem race conditions or pre-existing malicious files. The calls to `Path.exists()`, `Path.stat()`, `Path.read_bytes()`, and `Path.write_bytes()` follow symbolic links. The implementation does not reject sym ...[truncated 2749 chars]- Remediation
View remediation
