Skip to content

Update SharpCompress to 0.49.1 and re-arm its vulnerability alerting (SF-1864) - #2086

Closed
NickJosevski wants to merge 1 commit into
mainfrom
nj/sf-1864-sharpcompress-0.49
Closed

Update SharpCompress to 0.49.1 and re-arm its vulnerability alerting (SF-1864)#2086
NickJosevski wants to merge 1 commit into
mainfrom
nj/sf-1864-sharpcompress-0.49

Conversation

@NickJosevski

Copy link
Copy Markdown
Contributor

Resolves SF-1864.

Important

Alternative to #2085 — same change, landing on 0.49.1 instead of 0.48.0. Pick one; close the other. Both are drafts.

Warning

Draft: not ready to merge. Green CI is necessary but not sufficient here — see "How to review".

Why 0.49.1 rather than 0.48.0

0.48.0 was never a considered floor. When the CVE surfaced on 11 May, 0.48.0 (published 6 May) was simply the newest release and the first version outside the advisory's <= 0.47.4 range. Renovate raised it as the [SECURITY] bump, and that number got baked into the ticket title, the branch name and the original WIP commit. Everything above it shipped later:

Version Published
0.47.4 2026-04-05
0.48.0 2026-05-06 ← latest when the CVE landed
0.48.1 2026-05-14
0.49.0 2026-05-28
0.49.1 2026-05-29 ← this PR
0.50.0 2026-07-13
0.50.1 2026-07-25
1.0.0 unlisted (NuGet reports the 1900 sentinel date)

0.49.1 is also where Octopus Server independently landed (Octopus.Core.csproj).

Why not 0.50.x

0.50.0 changes Tar so it no longer attempts to decompress streams, and alters the detection API. TarGzipPackageExtractor and TarBzipPackageExtractor are built on layered decompression, so that is a materially riskier step — for no security benefit, since nothing security-related shipped after 0.48.0.

The one behaviour change in range, reviewed per call site

0.49.0 flipped WriterOptions.LeaveStreamOpen from true to false, so a writer now closes the stream it was handed. Every affected site:

Site Assessment
GitHubPackageDownloader.DeNestContents Writer and stream are nested usings → stream disposed twice. Stream.Dispose is idempotent, and nothing touches the stream after the writer. Safe.
UploadAwsS3Convention Returns targetArchivePath; never reads the stream after SaveTo. Data is flushed to disk under either default. Safe.
ZipPackageProvider / NugetPackageProvider Use the path overload of SaveTo — no stream ownership involved.
TarGzBuilder (tests) Already set LeaveStreamOpen = false explicitly, so unaffected by the default change.

Also in this PR: re-arming the alerting

All five references carried <NoWarn>NU1902</NoWarn>, added to unblock builds when the CVE was published. Left in place after an upgrade they would silently hide the next SharpCompress advisory, so this PR removes all five. With them gone the projects build clean and NuGet's audit raises no advisory for 0.49.1.

Were we actually vulnerable? Probably not

  • The advisory's vulnerable path is the archive-level IArchive.WriteToDirectory(). Calamari iterates entries itself and calls the per-entry APIs — the latter named in the advisory as already guarded.
  • ThrowIfPathTraversalAttempted independently resolves and bounds-checks every entry key, directory entries included, before anything is written.
  • The TAR symlink escalation is blocked because PackageExtractionOptions supplies a WriteSymbolicLink handler that refuses to create links — not, as previously discussed, because Calamari supplies no handler. That distinction is load-bearing: implementing real symlink support there would reopen the arbitrary-file-write primitive.

Automated tests

ExtractBlocksZipSlipViaDirectoryEntry crafts a zip containing a traversing directory entry (System.IO.Compression injects it, since normal writers won't emit one) and asserts the extractor throws and nothing lands outside the root. It passes on 0.37.2 too — so it evidences that Calamari's own guard blocks this vector, and deliberately does not claim to verify the library's fix, which was never confirmed upstream.

Verified locally: all affected projects build with 0 errors; 83 tests pass across PackageExtractorFixture and PackageExtractorUtilsFixture.

Not covered by executed tests: GitHubPackageDownloader's own fixtures need GitHub credentials (403 locally), and the Kubernetes EKS fixture that calls SaveTo is a live test. Both were assessed by reading the code, not by running it.

How to review this PR

Do not merge on green CI alone. #1913 passed Calamari's full suite, merged, then broke Server unpacking a consolidated package (An item with the same key has already been added in ExtractCalamariPackage). This is the one area of the repo where the suite is a known-inadequate gate.

Before this leaves draft:

  • Decide between this and Update SharpCompress to 0.48.0 and re-arm its vulnerability alerting (SF-1864) #2085, close the other.
  • Build Calamari and point a local Server at it (build-local.sh + OCTOPUS__Dev__CalamariPackagePath), then run a health check / deployment that unpacks a consolidated package.
  • Exercise the GitHub package downloader path with credentials, since that is where the LeaveStreamOpen change actually lands and local tests skip it.
  • Confirm whether a Requires Server Change label is needed. Expected not — ConsolidateCalamariPackages no longer references SharpCompress at all, so the old signature coupling that blocked Server 2025.4 does not apply.

Reducing risk

Out of scope, still open from the original discussion: extraction perf (~6s observed vs ~500ms expected, no benchmark exists), and whether this is backported to LTS branches.

…(SF-1864)

Alternative to #2085, which takes the same change to 0.48.0. Same
adaptations (WriterFactory.Open -> WriterFactory.OpenWriter,
ExtractionOptions) and the same removal of the five <NoWarn>NU1902</NoWarn>
elements, but landing on 0.49.1 instead.

Why 0.49.1 rather than 0.48.0: 0.48.0 was never a considered floor. When
the CVE surfaced on 11 May, 0.48.0 (published 6 May) was simply the newest
release and the first version outside the advisory's <= 0.47.4 range, so
Renovate raised it as the security bump and that number got baked into the
ticket, the branch name and the original WIP commit. 0.48.1 through 0.50.1
were all published afterwards. 0.49.1 is where Octopus Server independently
landed.

Why not further: 0.50.0 changes Tar so it no longer attempts to decompress
streams, and alters the detection API. Calamari's TarGzipPackageExtractor
and TarBzipPackageExtractor are built on layered decompression, so that is
a materially riskier step for no additional security benefit - nothing
security-related shipped after 0.48.0. 1.0.0 is unlisted (NuGet reports its
publish date as the 1900 sentinel) and is not a candidate.

The one behaviour change in range that touches Calamari is 0.49.0 flipping
WriterOptions.LeaveStreamOpen from true to false, so a writer now closes the
stream it was given. Reviewed per call site:

- GitHubPackageDownloader.DeNestContents - writer and stream are nested
  usings, so the stream is disposed twice; Stream.Dispose is idempotent, and
  nothing touches the stream after the writer is disposed.
- UploadAwsS3Convention - returns targetArchivePath and never reads the
  stream after SaveTo, and the data is flushed to disk under either default.
- ZipPackageProvider / NugetPackageProvider - use the path overload of
  SaveTo, so no stream ownership is involved.
- TarGzBuilder (tests) - already set LeaveStreamOpen = false explicitly, so
  it is unaffected by the change in default.

Verified: all affected projects build with 0 errors, NuGet's audit raises no
advisory for 0.49.1, and 83 tests pass across PackageExtractorFixture and
PackageExtractorUtilsFixture.

Not covered by executed tests: GitHubPackageDownloader's own fixtures need
GitHub credentials (they fail with 403 locally), and the Kubernetes EKS
fixture that calls SaveTo is a live test. Both were assessed by reading the
code rather than by running it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant