T09 · Insecure Skill Coding Practices
- Location
sentinel_restore.py:284- Finding
Workspace Boundary Bypass Through Path Traversal and Symlink Following
- Content
View full analysis
Vulnerability Details
File Location:
sentinel.py:249-263,sentinel.py:169-185,sentinel_restore.py:42-59,sentinel_restore.py:107-121, andsentinel_restore.py:284-290
Vulnerability Type: Path traversal and unsafe symlink handling
Risk Level: HighVulnerable Code
python # sentinel.py:249-263 def scan_critical_files(self) -> List[Path]: """Discover all critical files to monitor.""" critical_files = [] for pattern in self.config.CRITICAL_FILES: if '*' in pattern or '?' in pattern: # Glob pattern try: matches = list(self.workspace.glob(pattern)) critical_files.extend(matches) except Exception as e: self.logger.warning(f"Failed to glob pattern {pattern}: {e}") else: # Exact path filepath = self.workspace / pattern if filepath.exists(): critical_files.append(filepath)python # sentinel.py:169-185 def backup_file(self, filepath: Path, workspace_root: Path) -> Optional[Path]: """Create timestamped backup of a file.""" try: # Create backup path preserving directory structure rel_path = filepath.relative_to(workspace_root) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") backup_path = self.backup_root / timestamp / rel_path # Create parent directories backup_path.parent.mkdir(parents=True, exist_ok=True) # Copy file shutil.copy2(filepath, backup_path) self.logger.debug(f"Backed up: {filepath} -> {backup_path}") return backup_path except Exception as e: self.logger.error(f"Backup failed for {filepath}: {e}") return Nonepython # sentinel_restore.py:284-290 filepath = tool.workspace / args.file if not filepath.is_relative_to(tool.wo ...[truncated 3977 chars]- Remediation
View remediation
Remediation Suggestions
- Resolve the workspace once and resolve every candidate source and destination before use:
python workspace = Path(config_obj.WORKSPACE_ROOT).resolve(strict=True) candidate = (workspace / user_path).resolve(strict=False) if candidate != workspace and workspace not in candidate.parents: raise ValueError("Path escapes workspace") - Apply equivalent canonical containment checks to backup sources using the resolved backup root.
- Explicitly reject symbolic links in monitored files and restore destinations when links are not required. Use
lstat()and inspect every path component where appropriate. - Revalidate containment and symlink status immediately before opening or copying a file to reduce time-of-check/time-of-use exposure.
- Avoid writing through an existing destination path that may be a symlink. On supported platforms, use safe descriptor-based operations with no-follow semantics.
- Validate
CRITICAL_FILESduring initialization and reject absolute paths, traversal components, and paths that resolve outside the workspace. - Run Sentinel under a dedicated, least-privileged operating-system account with access only to the intended workspace and backup directory.
- Add regression tests covering
../traversal, absolute paths, source symlinks, destination symlinks, nested symlink components, and backup-directory escape attempts.
- Resolve the workspace once and resolve every candidate source and destination before use:
