Skip to content

Three RUSTSEC advisories in the dependency tree, and Cargo.lock is untracked #18

Open

Description

@Sadykhzadeh

Tested against v0.1.2-alpha.1 (24c4fb7).

Advisories

cargo audit on a fresh resolve of the workspace:

RUSTSEC-2023-0071  rsa 0.9.10             Marvin attack, timing side channel
                                          CVE-2023-49092, CVSS 5.9, no patched release exists
RUSTSEC-2026-0154  russh 0.46.0           unbounded 32-bit allocation
RUSTSEC-2026-0153  russh-cryptovec 0.7.3  unchecked CryptoVec allocation and growth
                                          both CVE-2026-46673, CVSS 7.5, patched in >= 0.60.3

Plus seven warnings. proc-macro-error 1.0.4 and five unic-* crates are unmaintained, and glib 0.18.5 has an unsoundness advisory. All of those arrive through Tauri and GTK.

I confirmed the shipped binaries carry these exact versions by reading the panic-path strings out of the released macOS and Windows executables, so this is not only a lockfile question.

Notes on each:

  • rsa has no fixed version in any 0.9 line. It reaches the tree through russh-keys, and the timing channel applies when Clavyn signs with a stored RSA key. Users on Ed25519 keys are not affected.
  • The two russh advisories describe frame-size handling in the SSH agent protocol. Clavyn rejects agent auth explicitly at connection.rs:72, which narrows the described vector, but russh-cryptovec sits on the general allocation path and 0.46.0 is fourteen minor versions behind.
  • Moving to russh 0.60.3 is not a version bump. The 0.5x line reorganised russh::keys and changed the Handler signatures, so connection.rs, session.rs and sftp.rs all need work.

Cargo.lock is not tracked

.gitignore lists Cargo.lock. For a workspace that produces shipped binaries the lockfile belongs in the repository. Without it:

  • every release resolves around 400 crates fresh, so two builds of the same tag can differ
  • a compromised or broken patch release of any transitive dependency lands in the next build with no diff to review
  • cargo audit results are not reproducible, because there is no recorded tree to audit

The npm side already does this correctly. desktop/package-lock.json and desktop/e2e/package-lock.json are both tracked, and CI runs npm ci.

No dependency gate in CI

.github/workflows/ci.yml runs cargo check, cargo test, vue-tsc, vitest and vite build. There is no cargo audit, no cargo deny, no cargo clippy, no npm audit and no Dependabot config. Nothing in the pipeline would have surfaced the three advisories above.

For reference, npm audit --omit=dev on desktop/ reports zero vulnerabilities today, so the production JavaScript tree is clean. The dev tree has five, including a critical in vitest that only applies when the Vitest UI server is listening, so it does not reach shipped code.

Suggested fix

Two steps, because they carry very different risk:

  1. Track Cargo.lock and add a cargo audit job to CI, with an audit.toml that ignores the three current advisories and a comment pointing back here. The job then catches anything new from day one.
  2. Upgrade russh to 0.60.3 or later as its own change, with the API migration and a manual connection test.

I have a PR for step 1.

Activity

  1. Sadykhzadeh commented on Sep 10, 2026

    @Sadykhzadeh
    MemberAuthor

    Working through the suppressions this issue's step 1 shipped, two corrections to
    the notes above — including one to this issue's own text — and a PR for the part
    that turns out to be live: #29.

    The two russh advisories are not the same finding. The body here says "the
    two russh advisories describe frame-size handling in the SSH agent protocol".
    That is right for RUSTSEC-2026-0154 and wrong for RUSTSEC-2026-0153.

    • RUSTSEC-2026-0154's package is russh, and its description is entirely
      agent-protocol frame-size validation. The suppression note is correct, and in
      fact understates the case: russh 0.46.0 has no agent implementation of its own.
      The code the advisory describes lives in russh-keys 0.46.0
      (src/agent/client.rs, src/agent/server.rs), which carries no advisory at
      all, and connection.rs:72 rejects agent auth before client::connect either
      way.
    • RUSTSEC-2026-0153 is the one about CryptoVec in "transport and compression
      buffers". Its note in .cargo/audit.toml was the un-justified one — just
      "Fixed in 0.60.3, which is part of the russh 0.5x/0.6x API break", with no
      vector note, which the file's own header requires.

    Of -0153's two paths, only one is live in 0.46.0.

    • Transport reads are bounded. russh-0.46.0/src/cipher/mod.rs rejects any
      packet whose declared length exceeds MAXIMUM_PACKET_LEN (256 KiB) before it
      resizes the read buffer.
    • zlib decompression is not. russh-0.46.0/src/compression.rs resizes its output
      buffer to output.len() * 2 on every partial-output status from flate2, with
      no ceiling. russh-cryptovec-0.7.3 panics explicitly when its realloc returns
      null, and the release profile's panic = "abort" turns that into process
      death, so every other open session dies with the one under attack.

    It is reachable: flate2 is a default feature and Config::default() offers
    [none, zlib, zlib@openssh.com]. Client preference means none wins against a
    normal server, but a server advertising zlib alone forces compression on. So the
    honest framing is a malicious or compromised server (or a hostile endpoint on a
    TOFU first connect) aborting the client — medium, not the advisory's 7.5, and no
    RCE or loss of confidentiality or integrity.

    #29 builds russh with default-features = false, which drops flate2 — its
    only default feature — and compiles the growth loop out entirely; the no-flate2
    decompress is a pass-through. clavyn-core is russh's only dependent, so
    nothing unifies the feature back on. Clavyn never negotiates compression. The PR
    also rewrites the -0153 note with the real residual, adds review-by dates
    enforced by a new expiry check in the audit job, pins the cargo-audit version
    CI builds, reports the seven informational advisories in a non-blocking step, and
    adds the back-reference to this issue that b252e52's message promised.

    The 0.46 → 0.60 upgrade stays here — #29 deliberately does not attempt it.

  2. Sadykhzadeh commented on Oct 2, 2026

    @Sadykhzadeh
    MemberAuthor

    Status

    Everything here except the rsa advisory itself is done.

    Cargo.lock is tracked. It is in the repository and CI resolves against it.

    The two russh advisories are gone. #98 migrated the workspace to russh 0.63.3, which took russh-cryptovec and russh-keys with it, so RUSTSEC-2026-0154 and RUSTSEC-2026-0153 no longer apply. As noted here, that was not a version bump — connection.rs, session.rs and sftp.rs all moved with it.

    There is a dependency gate in CI. The security-audit job runs cargo audit, npm audit --omit=dev on desktop/, and reports the development advisories separately without failing on them. .github/dependabot.yml covers cargo, npm and GitHub Actions.

    RUSTSEC-2023-0071 is suppressed with a review date, not silently. audit.toml carries the one entry, with why it is there — no rsa release fixes it, it reaches the tree through russh's rsa feature, which stays on so existing RSA keys keep working, and it only applies when signing with a stored RSA key. scripts/verify/check-audit-expiry.mjs runs in the same job and fails the build once review-by: 2026-12-31 passes, so the suppression cannot sit there unexamined.

    audit.toml points at this issue as its tracking issue, so leaving it open: the remaining work is to drop the suppression when an rsa release fixes the Marvin attack, or when russh no longer needs that feature.

  3. Sadykhzadeh commented on Oct 16, 2026

    @Sadykhzadeh
    MemberAuthor

    Status on current main:

    I'm keeping this open as the tracking issue for the rsa advisory, since audit.toml links here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

SecurityWhen there are security issues

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions