---
title: Prevent path traversal khi xử lý file trong app sandbox
impact: HIGH
impactDescription: Dùng filename từ user input hoặc server response để truy cập file mà không sanitize cho phép đọc file tùy ý trong sandbox, hoặc ghi đè file quan trọng như database và plist.
tags: swift, ios, path-traversal, file-access, sandbox, security
---

## Prevent path traversal khi xử lý file trong app sandbox

Khi tạo đường dẫn file từ input người dùng hoặc data từ server, phải validate path không chứa `../` và kết quả phải nằm trong thư mục cho phép. Luôn dùng `URL.appendingPathComponent` thay vì string concatenation cho path.

**Incorrect (path traversal qua tên file từ server):**

```swift
import Foundation

class FileDownloadManager {
    let downloadsDir = FileManager.default.urls(
        for: .documentDirectory, in: .userDomainMask
    )[0].appendingPathComponent("downloads")

    // !! filename từ server không được validate
    func saveDownloadedFile(data: Data, filename: String) throws {
        // Nếu filename = "../../Library/Application Support/default.realm" thì ghi đè DB!
        let filePath = downloadsDir.path + "/" + filename  // Path traversal!
        FileManager.default.createFile(atPath: filePath, contents: data)
    }

    // !! Đọc file theo path từ server response
    func readCachedFile(relativePath: String) -> Data? {
        let cacheDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
        let fullPath = cacheDir.appendingPathComponent(relativePath)  // Unsafe!
        return try? Data(contentsOf: fullPath)
    }
}
```

**Correct (sanitize và validate path):**

```swift
import Foundation

enum FileStorageError: LocalizedError {
    case pathTraversalDetected(String)
    case fileOutsideAllowedDirectory(URL)
    case invalidFilename(String)

    var errorDescription: String? {
        switch self {
        case .pathTraversalDetected(let name): return "Path traversal detected: \(name)"
        case .fileOutsideAllowedDirectory(let url): return "File outside allowed dir: \(url.path)"
        case .invalidFilename(let name): return "Invalid filename: \(name)"
        }
    }
}

struct SafeFileManager {
    let baseDirectory: URL

    // Validate filename: không có path separator, không có ".."
    func sanitizeFilename(_ filename: String) throws -> String {
        // Chỉ accept alphanumeric, dash, underscore, dot (không phải đầu)
        let allowedPattern = #"^[a-zA-Z0-9][a-zA-Z0-9._\-]{0,254}$"#
        let predicate = NSPredicate(format: "SELF MATCHES %@", allowedPattern)
        guard predicate.evaluate(with: filename) else {
            throw FileStorageError.invalidFilename(filename)
        }
        // Từ chối path separator và traversal
        if filename.contains("/") || filename.contains("..") || filename.contains("\0") {
            throw FileStorageError.pathTraversalDetected(filename)
        }
        return filename
    }

    // Verify resolved path nằm trong baseDirectory
    func validatePathContainment(_ url: URL) throws -> URL {
        let resolved = url.standardized
        let base = baseDirectory.standardized
        guard resolved.path.hasPrefix(base.path + "/") || resolved.path == base.path else {
            throw FileStorageError.fileOutsideAllowedDirectory(resolved)
        }
        return resolved
    }

    func saveFile(data: Data, filename: String) throws -> URL {
        let safeName = try sanitizeFilename(filename)
        let fileURL = baseDirectory.appendingPathComponent(safeName)
        let validatedURL = try validatePathContainment(fileURL)
        try data.write(to: validatedURL, options: [.atomic, .completeFileProtection])
        return validatedURL
    }

    func readFile(filename: String) throws -> Data {
        let safeName = try sanitizeFilename(filename)
        let fileURL = baseDirectory.appendingPathComponent(safeName)
        let validatedURL = try validatePathContainment(fileURL)
        return try Data(contentsOf: validatedURL)
    }
}
```

**Tools:** OWASP MASVS-STORAGE-3, SwiftLint custom rule (detect path + "/" + variable), Instruments
