Skip to content

SWIFT-6: ChiselKey/Options derive Debug, so a {:?} prints the raw passphrase — cannot be fixed until the Swift binding is on the published lineage #155

Description

@Xof

Split out of #103. The other two findings in that issue are fixed in #154 and #156; this one cannot be fixed on main, which is why it needs its own tracking issue rather than blocking #103.

Why it can't be fixed yet

chisel-ffi/ does not exist on origin/main. The Swift/UniFFI binding lives only on the local design/swift-binding branch, which sits on the orphaned pre-v1.0.0 lineagegit merge-base origin/main design/swift-binding reports no common ancestor. There is no file on the published tree to patch.

The defect (verbatim from the 2026-07-29 review)

chisel-ffi/src/types.rs:71 and :110:

#[derive(uniffi::Enum, Clone, Debug)]
pub enum ChiselKey { Raw { bytes: Vec<u8> }, Passphrase { phrase: String } }

Options embeds pub encryption_key: Option<ChiselKey> and is likewise #[derive(uniffi::Record, Clone, Debug)]. Both derive Debug on the plaintext secret.

This sits directly against the crate's own key-handling discipline two lines below: into_engine wraps everything in Zeroizing, and the root Cargo.toml pins zeroize specifically to wipe key material on drop. The Clone derive has the mirror problem — a cloned ChiselKey holds a plain Vec<u8>/String dropped without wiping.

Note the engine crate already does this correctly: crypto::Key hand-writes Debug to print Key::Raw(<redacted>) (src/crypto/mod.rs:42-49). The FFI layer just didn't inherit the discipline.

Why it matters

No call site formats these today, so nothing leaks right now — the derives are a standing trap. Any future tracing::debug!(?options), assert_eq! failure message, #[derive(Debug)] on an enclosing struct, or unwrap() on a Result<_, Options> prints the user's passphrase verbatim. On iOS those destinations (os_log, crash reporters) are routinely uploaded off-device.

Direction of a fix

Hand-write Debug for ChiselKey (and therefore for Options) to redact the payload — mirroring crypto::Key's existing impl — and drop Clone from ChiselKey unless a call site needs it.

Sequencing

This should be applied as part of porting the Swift binding onto the published lineage, not before — a fix committed to the orphaned branch cannot be PR'd and would likely be lost in the port. Whoever does that port should treat this as a checklist item.

Metadata

Metadata

Assignees

No one assigned

    Labels

    severity:designWrong shape: bad abstraction, unenforced invariant, doc contradicts codetype:securityTrust boundary, unsafe, hostile-input handling

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions