Dealing with RUSTSEC and patching deps of deps

We're running cargo-deny regularly to check for security advisories. It has flagged a couple of problems in recent months and I don't think we found a good way of dealing with this kind of problems.

In the past we worked with authors on fixes but in this case it's a dep of a dep of a dep and it'd mean prodding a couple of projects and so far the experience isn't the best since in general some projects are unmaintained and others are huge and can't be updated quickly enough.

As a current example, warp eventually depends on generic-array v0.12.3 which suffers from RUSTSEC-2020-0146:

generic-array v0.12.3
      β”œβ”€β”€ block-buffer v0.7.3
      β”‚   └── sha-1 v0.8.2
      β”‚       └── headers v0.3.3
      β”‚           └── warp v0.3.0

Instead of waiting for a new release of warp (which would need to use unreleased headers which would hopefully use sha-1 v0.9), is there something simpler that we can do?

It looks like patching in Cargo.toml would only work if we had a local copy of e.g. sha-1 since it isn't possible to patch within the same source. Once we have a local fork, we'd need to remember to get rid of it once the upstream is fixed.

In a commercial environment how do you deal with these situations? Wait for a fix, fork a local version and use patch or something else? What is your workflow?

Rustsec has a config file which lets you ignore individual reports.

[patch.crates-io] allows patching any crate you want, not just your dependency. So you can fix generic-array directly without patching other crates to use it.

To update to a fixed version of generic array, just run: cargo update -p generic-array

This will update the Cargo.lock file to the fixed version generic-array 0.12.4. No changes to Cargo.toml are required. This works because generic-array 0.12.4 is β€œsemver-compatible” with version 0.12.3.

(Edit: Ah, I see that generic-array 0.12.4 was just released three hours ago, shortly after you posted your question, so this solution was not available at the time.)

Thank you @kornel and @mbrubeck . In the end it was easy in this case since generic-array maintainers released backports so updating was trivial. Kudos to them!

I'm still not sure what is the best way to approach this in general.

  • I'd prefer not to silence security advisories -- it's a good selling point to the management to demonstrate that security and safety is taken seriously in Rust
  • when the change is trivial (like bumping up version in Cargo.toml), I create PRs but even if a dependency of warp gets updated, it can be months before warp gets updated to the new version (warp is just an example, I'm not trying to pick on it)
  • if a crate is unmaintained or the author is not responding, I could fork the crate but then I'd have to fork all its dependants as well which seems unnecessarily messy approach just to bump up a version
  • the simplest solution (at least in my head, but I'm sure there are edge cases I'm not aware of) would be allowing to use patch without having to use another source. I.e. I'd only want to override the version number. I could run into compatibility issues but so far it hasn't been a problem in the couple of cases I had to deal with.
  • things might get better in the future as more crates get mature enough. At the moment there are a lot of crates that don't really use semantic versioning since they're in their early 0.3s. It'd be a perfect world if all crates could deal with the problem the way generic-array maintainers did and provide semver backports.

Somewhat related -- I'd also find it useful to see security advisories on crates.io so that when choosing a crate I could choose the "safer" one. Maybe it'd also make sense for cargo publish to rant a bit when publishing a crate that uses deps with security advisories. Just to make it more obvious to authors that there might be a potential problem (and potentially an easy fix).

1 Like

I thought about using security advisories as a ranking factor on https://lib.rs, but in the end decided against it, because it's not clear which is safer:

  1. A crate that had a security issue reported and fixed it, or
  2. A crate that never had anything reported.

The case 2 may be just because nobody cared to look.

As a user I probably wouldn't want crates to be ranked that way but I'd be interested in knowing whether there are advisories or a crate depends on an unmaintained dep.

Maybe I'd also like to know whether a dep uses unsafe or not. Not sure how useful this would be in the real world but I guess I'd sleep better knowing there's no potential unsoundness.

Unfortunately, lack of unsafe doesn't mean code is safe.

If I were to write Rust malware, I'd deliberately take advantage of these things, so that cargo-geiger would give a big green seal of approval to my virus.

2 Likes

I don't want a perfect, automated solution, I know it can't be done, I'd just like to be able to make an informed decision and in general provide visibility and awareness.

We run cargo-deny daily to make sure we get notified when something is discovered. I think it'd be nice if maintainers could also see when their crates become dependent on unmaintained or vulnerable crates and such notifications would become a standard practice/workflow.

1 Like