T09 · Insecure Skill Coding Practices
Error
- Location
- run.py:145
- Finding
- Unsafe Archive Extraction Permits File Overwrite Through Link Entries## Vulnerability Details **File Location**: `run.py:145-150` **Vulnerability Type**: Unsafe archive extraction **Risk Level**: High **Vulnerable Code**: ```python # Extract bio = io.BytesIO(blob) with tarfile.open(fileobj=bio, mode="r:gz") as tar: # Security check for Zip Slip for member in tar.getmembers(): if os.path.isabs(member.name) or ".." in member.name: raise Exception(f"Security Error: Archive contains unsafe path {member.name}") tar.extractall(path=".") # Extract to current dir, overwriting ``` ### Technical Analysis The restore operation treats a database-supplied archive as trusted after checking only the textual names of its members. The check does not reject symbolic links, hard links, device nodes, or other special archive entries. It also does not validate link targets or resolve final destination paths before extraction. An archive can contain a link entry whose member name appears safe but whose target refers outside the current directory. Subsequent entries may then write through that link. The call to `extractall()` also deliberately overwrites existing files in the current working directory. Because the archive is retrieved using a user-supplied DSN, an attacker who controls that database—or who acquires credentials for the legitimate transfer database—can supply a crafted archive. ### Attack Path 1. The attacker creates or compromises a MySQL-compatible database accessible to the victim. 2. The attacker creates a `teleport` table containing a malicious gzip-compressed tar archive under `id=1`. 3. The archive includes a symbolic or hard link with a benign member name but an unsafe target, followed by a file written through that link. 4. The attacker gives the victim the malicious DSN, or replaces the archive in a legitimate transfer database. 5. The victim runs `run.py --action restore --dsn ...`. 6. The member-name checks pass because the unsafe destina ...[truncated 793 chars]
- Remediation
- ## Remediation Suggestions - Extract into a newly created, permission-restricted staging directory rather than directly into the current workspace. - Permit only regular files and directories. Reject symbolic links, hard links, device nodes, FIFOs, and other special member types. - Resolve each proposed destination with `pathlib.Path.resolve()` and verify that it remains beneath the resolved staging-directory root. - Validate both member names and link targets. - Use a safe extraction filter supported by the deployed Python version, while retaining explicit validation for compatibility. - Present a manifest and require confirmation before replacing existing workspace files. - Copy validated files from staging into the destination using controlled overwrite rules rather than calling unrestricted `extractall()`. - Run restoration with the least-privileged account required for the workspace.
