T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- scripts/backup-telos.ts:88
- Finding
- Unvalidated Backup and Restore Paths Permit Arbitrary Filesystem Access<![CDATA[ ## Vulnerability Details **File Location**: `scripts/backup-telos.ts:66-67, 88-108, 169-187` **Vulnerability Type**: Path traversal and unrestricted filesystem copy/overwrite **Risk Level**: High ### Vulnerable Code ```ts const timestamp = getTimestamp(); const name = customName ? `${SNAPSHOT_PREFIX}${customName}-${timestamp}` : `${SNAPSHOT_PREFIX}${timestamp}`; const snapshotPath = join(SNAPSHOTS_DIR, name); ``` ```ts function cmdRestore(snapshotName: string) { const snapshotPath = snapshotName.startsWith("/") ? snapshotName : join(SNAPSHOTS_DIR, snapshotName.startsWith(SNAPSHOT_PREFIX) ? snapshotName : `${SNAPSHOT_PREFIX}${snapshotName}`); if (!existsSync(snapshotPath)) { console.error(`Snapshot not found: ${snapshotPath}`); cmdList(); process.exit(1); } // Safety: backup current state before restoring if (existsSync(TELOS_DIR)) { const safetyName = `${SNAPSHOT_PREFIX}pre-restore-${getTimestamp()}`; const safetyPath = join(SNAPSHOTS_DIR, safetyName); mkdirSync(SNAPSHOTS_DIR, { recursive: true }); cpSync(TELOS_DIR, safetyPath, { recursive: true }); console.log(`Safety snapshot created: ${safetyName}`); } // Restore rmSync(TELOS_DIR, { recursive: true, force: true }); cpSync(snapshotPath, TELOS_DIR, { recursive: true }); console.log(`\nRestored from: ${basename(snapshotPath)}`); console.log(`Location: ${TELOS_DIR}`); } ``` ```ts function cmdRestoreFile(filename: string, version: string) { const backupPath = join(BACKUPS_DIR, version); if (!existsSync(backupPath)) { console.error(`Backup not found: ${backupPath}`); cmdHistory(filename); process.exit(1); } const targetPath = join(TELOS_DIR, filename); // Backup current version before restoring if (existsSync(targetPath)) { mkdirSync(BACKUPS_DIR, { recursive: true }); const timestamp = getTimestamp(); const safetyBackup = `${filename.replace(".md", "")}_pre-restore_${timestamp}.md`; cpSync(targ ...[truncated 2322 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Reject absolute paths and all arguments containing path separators, `.` segments, or `..` segments. 2. Restrict snapshot names to a conservative pattern such as: ```ts const SAFE_SNAPSHOT = /^telos-snapshot-[A-Za-z0-9_-]+$/; ``` 3. Allowlist `filename` against the same fixed TELOS filename list used by `update-telos.ts`. 4. Resolve and verify every path before accessing it: ```ts import { resolve, relative, isAbsolute } from "path"; function resolveWithin(parent: string, child: string): string { if (isAbsolute(child)) throw new Error("Absolute paths are not allowed"); const base = resolve(parent); const candidate = resolve(base, child); const rel = relative(base, candidate); if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) { throw new Error("Path escapes the allowed directory"); } return candidate; } ``` 5. Verify that a full-restore source is a directory and conforms to the expected snapshot structure. 6. Verify that a file-restore source is a regular Markdown file, not a directory or symbolic link. 7. Consider rejecting symbolic links throughout snapshot creation and restoration. 8. Stage restored data in a temporary directory, validate it, and use an atomic rename instead of deleting the live directory first. 9. Require explicit user confirmation that displays the canonical source and destination before any destructive restore. ]]>
