fix(security): apply 4 vulnerability fixes from security audit

1. Share password bypass (HIGH): enforce password check in get_shared_link_by_token,
   verify_shared_link_password now returns ShareDto only on correct password.
2. WebDAV MOVE ownership (MEDIUM): add assert_owner on destination parent folder
   for file moves in both PathResolver and legacy branches.
3. Path traversal defense-in-depth (LOW): add reject_path_traversal() to WebDAV,
   CalDAV, and CardDAV handlers rejecting '..' segments at HTTP boundary.
4. Setup race condition (LOW): atomic INSERT ... ON CONFLICT DO NOTHING in
   try_claim_initialization prevents duplicate admin creation.
This commit is contained in:
Dionisio
2026-03-05 16:09:37 +01:00
parent 33cfb0faef
commit 4197cc3b7b
9 changed files with 198 additions and 14 deletions
@@ -97,4 +97,28 @@ impl SettingsRepository for SettingsPgRepository {
Ok(())
}
/// Atomically claim system initialization using INSERT … ON CONFLICT DO NOTHING.
///
/// Only the first caller that inserts the row gets `rows_affected == 1`;
/// concurrent callers see 0 rows affected and receive `false`.
async fn try_claim_initialization(
&self,
admin_user_id: &str,
) -> Result<bool, DomainError> {
let result = sqlx::query(
"INSERT INTO auth.admin_settings (key, value, category, is_secret, updated_by, updated_at)
VALUES ('system_initialized', 'true', 'system', false, $1, NOW())
ON CONFLICT (key) DO NOTHING"
)
.bind(admin_user_id)
.execute(self.pool.as_ref())
.await
.map_err(|e| DomainError::new(
ErrorKind::InternalError, "Settings", format!("DB error: {}", e),
))?;
// rows_affected == 1 means we inserted; 0 means another caller already did
Ok(result.rows_affected() == 1)
}
}