github charmbracelet/soft-serve v0.12.0

4 hours ago

This release fixes five security issues, one of them critical. Please upgrade.

Huge thanks to @arpitjain099, @sondt99, @tonghuaroot, @Faze-up, @456789TZ, @kodareef5, and @thientd for reporting these.

Security

Privilege escalation to global admin (GHSA-952g-9vq9-782q, critical)

The permission check written for repository commands was also used to guard
the global user and settings commands. Because that check reads the
command's first argument as a repository name, any authenticated user could
create a repository named to match and let the check pass, reaching commands
meant for server administrators only.

Global commands now use a dedicated server-admin gate that never consults
repository access. Two related escalations found alongside it are fixed as
well: a read-write collaborator could grant admin access to any account, and
could remove or downgrade a collaborator ranked above them. Both are now
capped at the caller's own access level, with server admins exempt.

Vulnerable SSH library (GHSA-v57m-p5gf-9mf5, high)

The SSH server reached code paths in golang.org/x/crypto/ssh that were
fixed upstream in 0.52.0. Dependencies are updated, along with the Go
toolchain, clearing fifteen govulncheck findings in total.

Server-side request forgery via repo import and mirror sync (GHSA-vpj5-m56f-8h3f, medium)

Any authenticated user could import a repository from an arbitrary URL,
including loopback, private, and cloud metadata addresses. Scheduled mirror
syncs re-fetched that URL every ten minutes, so a single import kept the
access alive with no further interaction.

Remotes are now checked against private and internal ranges before any
network access, and re-checked before each sync. Because the fetch itself is
done by a git subprocess that makes its own network decisions, redirect
following is disabled for these operations and validated hostnames are
pinned to the address that was checked. Addresses in non-standard forms such
as 0177.0.0.1 are rejected rather than resolved, and git:// remotes are
now validated too.

One behavior change worth noting: moved repositories must be imported from
their current URL, since redirects are no longer followed.

SSRF guard bypass via IPv6 transition addresses (GHSA-3qq2-64gj-j5qf, medium)

The guard above reasoned about IPv4 and IPv6 as separate address spaces.
Several IPv6 forms carry an IPv4 address inside them, and those went
uninspected, so an internal host could be named in a form the check read as
ordinary public IPv6. The NAT64 encoding of the cloud metadata endpoint,
64:ff9b::a9fe:a9fe, passed.

6to4, both NAT64 prefixes, Teredo, the deprecated IPv4-compatible form, and
the 6to4 relay anycast range are now blocked in full rather than decoded and
re-checked. That removes the whole class of bypass instead of depending on
each decoding being implemented correctly. The consequence: such an encoding
of a genuinely public address is now rejected too.

Cross-repository disclosure of Git LFS lock metadata (GHSA-xqg9-4q65-m2wf, medium)

The Git LFS lock endpoints checked the caller's permissions against the
repository in the request URL, but looked locks up by their global ID alone.
Anyone with write access to any repository could walk lock IDs and read locks
belonging to repositories they cannot access, disclosing file paths, who held
the lock, and when it was taken. Lock file paths from a private repository
are themselves sensitive, since they reveal what a project is working on.

Locks are now looked up scoped to the repository being requested, matching
how every other lock query already behaved.

Also hardened

SSH sessions are now isolated from one another in the underlying wish
library, and webhook delivery reads are scoped to the named repository so
stored request and response bodies cannot be read across repositories.

Changelog

New!

Fixed

Docs

Other stuff


Verifying the artifacts

First, download the checksums.txt file and the checksums.txt.sigstore.json file files, for example, with wget:

wget 'https://github.com/charmbracelet/soft-serve/releases/download/v0.12.0/checksums.txt'
wget 'https://github.com/charmbracelet/soft-serve/releases/download/v0.12.0/checksums.txt.sigstore.json'

Then, verify it using cosign:

cosign verify-blob \
  --certificate-identity 'https://github.com/charmbracelet/meta/.github/workflows/goreleaser.yml@refs/heads/main' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  --bundle 'checksums.txt.sigstore.json' \
  ./checksums.txt

If the output is Verified OK, you can safely use it to verify the checksums of other artifacts you downloaded from the release using sha256sum:

sha256sum --ignore-missing -c checksums.txt

Done! You artifacts are now verified!

The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.

Don't miss a new soft-serve release

NewReleases is sending notifications on new releases.