Summary
File upload commands (bundles, images, deobfuscation, sync import) currently open files directly without validating resolved paths. A malicious or misconfigured symlink could cause the CLI to read files outside the intended directory, creating a path traversal vulnerability. This issue adds a secure file-opening package that resolves symlinks and verifies the final path is within an expected directory boundary.
Implementation Plan
Files to Create/Modify
- Create:
internal/secureopen/secureopen.go — Core secure file-opening logic
- Create:
internal/secureopen/secureopen_test.go — Comprehensive tests
- Modify:
internal/cli/bundles/upload.go — Use secureopen.SecureOpen()
- Modify:
internal/cli/apks/upload.go — Use secureopen.SecureOpen()
- Modify:
internal/cli/images/upload.go — Use secureopen.SecureOpen()
- Modify:
internal/cli/deobfuscation/upload.go — Use secureopen.SecureOpen()
- Modify: Other commands that open user-specified files
Testing
Acceptance Criteria
Summary
File upload commands (bundles, images, deobfuscation, sync import) currently open files directly without validating resolved paths. A malicious or misconfigured symlink could cause the CLI to read files outside the intended directory, creating a path traversal vulnerability. This issue adds a secure file-opening package that resolves symlinks and verifies the final path is within an expected directory boundary.
Implementation Plan
secureopenpackage with a primary function:SecureOpen(path string, allowedDirs ...string) (*os.File, error)SecureOpen:filepath.Clean()filepath.EvalSymlinks()filepath.Abs()allowedDirsprovided, verify the resolved path is within the current working directorySecureOpenFile(path string, flag int, perm os.FileMode, allowedDirs ...string) (*os.File, error)variant for custom open flags"file path resolves outside allowed directory: resolved %s, allowed %s""failed to resolve symlinks: %w"bundles upload— bundle fileapks upload— APK fileimages upload— image filedeobfuscation upload— mapping filesync import— import fileauth login --service-account— service account key file--filepath's parent directoryFiles to Create/Modify
internal/secureopen/secureopen.go— Core secure file-opening logicinternal/secureopen/secureopen_test.go— Comprehensive testsinternal/cli/bundles/upload.go— Usesecureopen.SecureOpen()internal/cli/apks/upload.go— Usesecureopen.SecureOpen()internal/cli/images/upload.go— Usesecureopen.SecureOpen()internal/cli/deobfuscation/upload.go— Usesecureopen.SecureOpen()Testing
../traversal attempts are blockedallowedDirsdefaults to current working directoryallowedDirs— file in any one of them is acceptedAcceptance Criteria
secureopen.SecureOpen()resolves symlinks before opening files../or symlinks is preventedsecureopenfor file access