T09 · Insecure Skill Coding Practices
- Location
scripts/lobster_doctor.py:829- Finding
Cleanup Performs Destructive Workspace Changes Without Mandatory Preview or Confirmation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/lobster_doctor.py:829-971
Vulnerability Type: Unsafe destructive file operations without confirmation
Risk Level: MediumEvidence
python def cmd_cleanup(dry_run=False): if dry_run: print(f"🦞 龙虾医生 — 模拟清理 ({datetime.now().strftime('%Y-%m-%d %H:%M')})\n") else: print(f"🦞 龙虾医生 — 自动清理 ({datetime.now().strftime('%Y-%m-%d %H:%M')})\n") today = datetime.now().strftime('%Y-%m-%d') backup = BACKUP_DIR / today if not dry_run: backup.mkdir(parents=True, exist_ok=True) # Clean stale scripts from the workspace root. stale_extensions = {'.py', '.js', '.html', '.txt', '.log', '.json'} for f in list(WORKSPACE.iterdir()): if not f.is_file() or f.name in CORE_FILES: continue if f.name.startswith('.'): continue if f.suffix in stale_extensions and file_age_days(f) > STALE_DAYS_PY_JS_HTML: if dry_run: print(f" 🗑️ [模拟] {f.relative_to(WORKSPACE)}") else: f.rename(backup / f.name) # Remove empty directories. for d in list(WORKSPACE.rglob('*')): if not d.is_dir() or d == WORKSPACE: continue if any(part in PROTECTED_DIRS for part in d.parts): continue try: if not any(d.iterdir()): if not dry_run: d.rmdir() except (OSError, PermissionError): pass # Archive old memory logs. memory_dir = WORKSPACE / "memory" if memory_dir.exists(): cutoff = datetime.now() - timedelta(days=MEMORY_LOG_MAX_DAYS) for f in memory_dir.glob('*.md'): if f.name == 'README.md' or f.name == 'heartbeat-state.json': continue try: mtime = datetime.fromtimestamp(f.stat().st_mtime) ...[truncated 3665 chars]- Remediation
View remediation
Remediation Suggestions
-
Make preview mode the default:
- Run cleanup as a dry run unless an explicit
--applyflag is present. - Do not treat the absence of
--dry-runas authorization for mutation.
- Run cleanup as a dry run unless an explicit
-
Require informed confirmation:
- Produce an exact manifest containing every source path, destination path, selection reason, size, and operation.
- Require interactive confirmation or a separately issued apply command.
- Consider binding approval to a hash of the preview manifest so the applied set cannot differ from the reviewed set.
-
Protect memory consistently:
- Remove memory processing from generic cleanup.
- Require the dedicated
memory-archive --applycommand for memory changes. - Preserve files marked as important and expose retention thresholds as explicit configuration.
-
Replace broad age-based classification:
- Use an allowlist of known temporary directories and filename patterns.
- Never classify arbitrary
.py,.js,.json, or.mdfiles as disposable solely because of modification time. - Require per-file approval for files outside dedicated cache or temporary directories.
-
Improve recovery:
- Use collision-resistant, path-preserving backup destinations.
- Write a machine-readable restoration manifest.
- Implement an atomic rollback command and verify backups before moving source files.
-
Add regression tests proving that protected files, memory files, intentionally duplicated paths, and unapproved files remain unchanged.
-
