T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/cache_manager.py:17
- Finding
- Strava Activity and Health Data Cached Without Restrictive File Permissions## Vulnerability Details **File Location**: `scripts/cache_manager.py:17-34` **Vulnerability Type**: Sensitive data stored with default filesystem permissions **Risk Level**: Medium ```python def ensure_cache_dir(): """Create cache directory if it doesn't exist.""" CACHE_DIR.mkdir(parents=True, exist_ok=True) def load_cached_activities(): """Load activities from cache.""" ensure_cache_dir() if not ACTIVITIES_CACHE.exists(): return [] with open(ACTIVITIES_CACHE) as f: return json.load(f) def save_activities_to_cache(activities): """Save activities to cache.""" ensure_cache_dir() with open(ACTIVITIES_CACHE, 'w') as f: json.dump(activities, f, indent=2) # Update last sync time with open(LAST_SYNC_FILE, 'w') as f: f.write(datetime.now().isoformat()) ``` ### Technical Analysis The cache directory and files are created without explicit permission modes. Their effective permissions therefore depend on the user's current `umask`. On a shared host or under a permissive configuration, other local users or processes may be able to read the files. `monitor_new_rides.py` passes full activity objects returned by Strava to the cache manager. These objects can include activity names, timestamps, athlete-related fields, performance metrics, and potentially route or location summaries. The cache also has no retention limit and can grow indefinitely as new activities are merged. ### Attack Path 1. The user enables automatic monitoring or runs `monitor_new_rides.py`. 2. The script retrieves recent activity objects from Strava. 3. `update_cache_with_new_activities()` passes those objects to `save_activities_to_cache()`. 4. The objects are written to `~/.cache/strava/activities.json` using permissions inherited from the environment. 5. A local user or compromised process with read access to the file extracts fitness, timestamp, and pote ...[truncated 381 chars]
- Remediation
- ## Remediation Suggestions - Create `~/.cache/strava` with mode `0700`. - Create activity and synchronization files with mode `0600`, independent of the ambient `umask`. - Apply restrictive permissions to existing files before reading or updating them. - Use atomic writes through a securely created temporary file followed by `os.replace()`. - Cache only the activity IDs and fields required to detect new rides rather than complete API responses. - Add a configurable retention limit and remove stale activity records. - Document that the cache contains sensitive activity information. Example hardening: ```python import os import tempfile def ensure_cache_dir(): CACHE_DIR.mkdir(parents=True, exist_ok=True, mode=0o700) CACHE_DIR.chmod(0o700) def save_private_json(path, value): fd, temporary_path = tempfile.mkstemp(dir=CACHE_DIR, prefix=".tmp-") try: os.fchmod(fd, 0o600) with os.fdopen(fd, "w") as stream: json.dump(value, stream, indent=2) os.replace(temporary_path, path) path.chmod(0o600) except Exception: try: os.unlink(temporary_path) except FileNotFoundError: pass raise ```
