release: v0.7.1 — Security-Patch (R-01 bis R-06)
Sanctum Release / Build & Release (Windows x86_64) (push) Canceled after 0s

- R-01: Bereinigung verbliebener Restbehauptungen in Doku und Code (LEGAL.md, README.md, QUICKSTART.md, main.rs, crypto/storage/recovery/verify.rs)
- R-02: Lückenloser Carrier-Schutz in SanctumFs::copy (Quelle & Ziel) und sync (Pull-Skip & Push-Schutz)
- R-03: Shared Dateinamen-Validierung (validate_node_name) in pathutil.rs, durchgesetzt in storage.rs und vfs.rs
- R-04: Fail-closed Release-Packaging & obligatorische Minisign-Signatur in CI (.gitea/workflows/release.yaml) und Scripts
- R-05: Session-Token Beseitigung im argv: In-Process Win32 WNetAddConnection2W/WNetCancelConnection2W, kein gio argv-Token, Multi-Auth HTTP Middleware (Basic Auth, X-Sanctum-Token, Path-Fallback) mit 401 WWW-Authenticate
- R-06: Sofortiges Löschen von SANCTUM_RECOVERY_KEY aus der Prozessumgebung
This commit is contained in:
2026-09-18 19:49:38 +02:00
parent 436790abf0
commit 1cdb30147b
24 changed files with 663 additions and 174 deletions
+7 -5
View File
@@ -639,7 +639,7 @@ impl Database {
Ok(carrier_node_id)
}
/// Initialisiert das Datenbankschema mit Unterstützung für Plausible Deniability (optionaler Hidden Vault).
/// Initialisiert das Datenbankschema mit Unterstützung für Dual-Vault (optionaler Hidden Vault).
/// Sowohl Standard-Container als auch Container mit Hidden Vault besitzen eine bit- und schemagleiche Struktur:
/// - 2 Slots in der meta-Tabelle (Slot 0 + Slot 1 mit echtem KEK oder ununterscheidbarem CSPRNG-Rauschen)
/// - 2 Root-Knoten (id=1 für Vault 0, id=2 für Vault 1)
@@ -720,7 +720,7 @@ impl Database {
params![now, now],
)?;
// Slot 1: Entweder echter Hidden Vault ODER ununterscheidbares kryptografisches Rauschen (Plausible Deniability)
// Slot 1: Entweder echter Hidden Vault ODER CSPRNG-Rauschen (Dummy-Slot-Längenparität)
if let Some((h_salt, h_params, h_wrapped, h_nonce, h_tag)) = hidden {
let params_json_1 = serde_json::to_string(h_params)?;
conn.execute(
@@ -758,7 +758,7 @@ impl Database {
Ok(())
}
/// Initialisiert das Datenbankschema für einen Standard-Container (mit Dummy-Slot für Plausible Deniability).
/// Initialisiert das Datenbankschema für einen Standard-Container (mit Dummy-Slot-Längenparität).
pub fn init_schema(
&self,
salt: &[u8; 16],
@@ -1191,6 +1191,7 @@ impl Database {
is_dir: bool,
dek: &[u8; 32],
) -> Result<NodeRecord> {
crate::pathutil::validate_node_name(name)?;
let now = current_timestamp();
let conn = self.conn.lock().unwrap();
@@ -1299,6 +1300,7 @@ impl Database {
dek: &[u8; 32],
) -> Result<()> {
self.assert_not_carrier(id)?;
crate::pathutil::validate_node_name(new_name)?;
let now = current_timestamp();
let conn = self.conn.lock().unwrap();
let stored_name = if vault_id == 1 {
@@ -1590,7 +1592,7 @@ impl Database {
)?;
}
// Falls Slot 1 nicht existiert (z. B. altes Single-Slot Backup), erzeuge Dummy-Slot für Plausible Deniability
// Falls Slot 1 nicht existiert (z. B. altes Single-Slot Backup), erzeuge Dummy-Slot für Längenparität
if !has_slot1 {
let (dummy_dek, dummy_nonce, dummy_tag, dummy_salt) = generate_dummy_slot();
let dummy_params_json = serde_json::to_string(&KdfParams::default())?;
@@ -1910,7 +1912,7 @@ mod tests {
params![hidden_file.id],
|r| r.get(0),
).unwrap();
// Plausible Deniability: Kein $h$-Präfix, kein Klartext
// Dual-Vault Isolation: Kein $h$-Präfix, kein Klartext
assert!(!raw_name_v1.starts_with("$h$"), "Hidden Vault Dateiname darf kein $h$-Präfix mehr besitzen");
assert!(!raw_name_v1.contains("classified_leak"), "Plaintext darf keinesfalls in SQLite DB auftauchen");