fix(security): VULN-01 admin escalation + VULN-02 path traversal hardening
VULN-01 - Admin privilege escalation: - Harden register() to reject is_admin=true - Add /api/setup endpoint with setup_token for initial admin creation - Add SetupAdminDto and setup_token to AppState - Remove dead code from auth handler VULN-02 - Path traversal (CVSS ~8.6): - Solution A+E: Harden StoragePath constructors (from_string, new, join) to strip '..' and '.' segments and reject slash injection - Solution B: resolve_path() now returns Result<PathBuf>, calls validate_path() internally, and verifies resolved path stays under root - Update StoragePort trait signature to return Result<PathBuf, DomainError> - Remove dead code: FilePathResolutionPort, StorageVerificationPort, DirectoryManagementPort (declared but never implemented) - Add 17 security tests covering traversal attack vectors
This commit is contained in:
@@ -10,8 +10,10 @@ use super::storage_ports::{FileReadPort, FileWritePort};
|
||||
|
||||
/// Secondary port for storage operations
|
||||
pub trait StoragePort: Send + Sync + 'static {
|
||||
/// Resolves a domain path to a physical path
|
||||
fn resolve_path(&self, storage_path: &StoragePath) -> PathBuf;
|
||||
/// Resolves a domain path to a physical path.
|
||||
///
|
||||
/// Returns an error if the path contains unsafe segments (defense-in-depth).
|
||||
fn resolve_path(&self, storage_path: &StoragePath) -> Result<PathBuf, DomainError>;
|
||||
|
||||
/// Creates directories if they don't exist
|
||||
async fn ensure_directory(&self, storage_path: &StoragePath) -> Result<(), DomainError>;
|
||||
|
||||
@@ -303,30 +303,6 @@ pub trait FileWritePort: Send + Sync + 'static {
|
||||
// Auxiliary ports (unchanged)
|
||||
// ─────────────────────────────────────────────────────
|
||||
|
||||
/// Secondary port for file path resolution
|
||||
pub trait FilePathResolutionPort: Send + Sync + 'static {
|
||||
/// Gets the storage path of a file
|
||||
async fn get_file_path(&self, id: &str) -> Result<StoragePath, DomainError>;
|
||||
|
||||
/// Resolves a domain path to a physical path
|
||||
fn resolve_path(&self, storage_path: &StoragePath) -> PathBuf;
|
||||
}
|
||||
|
||||
/// Secondary port for file/directory existence verification
|
||||
pub trait StorageVerificationPort: Send + Sync + 'static {
|
||||
/// Checks whether a file exists at the given path
|
||||
async fn file_exists(&self, storage_path: &StoragePath) -> Result<bool, DomainError>;
|
||||
|
||||
/// Checks whether a directory exists at the given path
|
||||
async fn directory_exists(&self, storage_path: &StoragePath) -> Result<bool, DomainError>;
|
||||
}
|
||||
|
||||
/// Secondary port for directory management
|
||||
pub trait DirectoryManagementPort: Send + Sync + 'static {
|
||||
/// Creates directories if they do not exist
|
||||
async fn ensure_directory(&self, storage_path: &StoragePath) -> Result<(), DomainError>;
|
||||
}
|
||||
|
||||
/// Secondary port for storage usage management
|
||||
pub trait StorageUsagePort: Send + Sync + 'static {
|
||||
/// Updates storage usage statistics for a user
|
||||
|
||||
Reference in New Issue
Block a user