CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-PCHF-49FH-W34R

Soft Serve, Hard Landing: The SSH Identity Crisis (CVE-2026-24058)

Alon Barad
Alon Barad
Software Engineer

Feb 15, 2026·7 min read·36 visits

Executive Summary (TL;DR)

Soft Serve trusted the identity of an 'offered' public key before verifying the signature. An attacker can offer an Admin key (fail signature) then offer their own key (pass signature), but the server retains the Admin identity in the session context. Result: Full Account Takeover.

A critical authentication bypass in Charmbracelet's Soft Serve allows attackers to impersonate administrators by exploiting a logic flaw in the SSH handshake state management. By offering a victim's key before authenticating with their own, an attacker can trick the server into granting the victim's privileges.

The Hook: When Git Meets the Jedi Mind Trick

Soft Serve is a beautiful piece of software. It’s a self-hostable Git server for the command line, built by Charmbracelet, a team known for making the terminal look better than most GUIs. It uses SSH for everything—authentication, repository access, and even the UI itself (via TUI). It's slick, modern, and written in Go.

But here's the thing about modern SSH servers: managing state is a nightmare. Unlike HTTP, which is stateless (mostly), SSH is a persistent tunnel with a complex handshake dance. If you trip over your own feet during that dance, you faceplant hard. And that is exactly what happened here.

CVE-2026-24058 isn't a buffer overflow. We aren't smashing the stack or spraying the heap. We are gaslighting the server. We are performing a Jedi Mind Trick. We tell the server, "I am the Admin," and even though we can't prove it, the server nods and writes it down. Later, when we actually prove we are "Nobody," the server looks at its notes, sees "Admin," and hands over the keys to the kingdom. It is a classic State Pollution vulnerability, and it is devastatingly simple.

The Flaw: The 'Offer' vs. 'Sign' Trap

To understand this bug, you need to understand a nuance of the SSH protocol: Public Key Authentication is a two-step process.

  1. The Offer (Query): The client says, "Hey, I have this public key (Key A). Do you accept it?" The server checks if Key A is in its authorized_keys list. If yes, it says "Sure, prove you own it."
  2. The Signature: The client then signs a blob of data with the private key corresponding to Key A. The server verifies the signature. If it matches, you are in.

Most SSH clients try multiple keys. They might offer Key A, realize they don't have the passphrase, and then offer Key B.

The vulnerability in Soft Serve (specifically in how it used the wish middleware) was a failure to clean up the workspace. When the client performed Step 1 (The Offer) with a victim's key, the server's PublicKeyHandler immediately resolved that key to a User ID and stuffed it into the session context (proto.ContextKeyUser).

> [!WARNING] > The server committed the sin of premature optimization: it assumed that if you offer a key, you will eventually sign with it.

If the signature verification failed (because you don't actually have the Admin's private key), the SSH protocol correctly rejected that specific authentication attempt. However, the Session Context was already polluted. The variable proto.ContextKeyUser still held the Admin's user object. When the attacker subsequently authenticated with their own valid, low-privilege key, the server verified the crypto correctly but forgot to clear the stale "Admin" user from the context. The code proceeded to authorize the session based on the stale data, not the key that actually passed verification.

The Code: The Smoking Gun

Let's look at the logic flow that caused this. The vulnerability lived in the intersection of the middleware chain and the context handling.

In the vulnerable version, the PublicKeyHandler looked something like this (simplified for clarity):

// VULNERABLE LOGIC
func PublicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool {
    // 1. Resolve user from the offered key
    user, err := backend.UserByPublicKey(key)
    if err == nil {
        // CRITICAL FLAW: Setting the user in the context during the handshake
        // simply because the key exists in the database.
        ctx.SetValue(proto.ContextKeyUser, user)
    }
    return true // Allow the key to proceed to signature check
}

The fix involves a philosophical shift: Don't trust the context during the handshake. The patch (Commit 8539f9a) moves the identity resolution to after the connection is fully established, using the key that actually signed the request.

Here is a snippet of the regression test added in the patch, which perfectly illustrates the attack flow:

// From pkg/ssh/middleware_test.go (The Fix)
 
// Step 1: Attacker offers Admin Key
// The mock context gets polluted
mockCtx.SetValue(proto.ContextKeyUser, adminUser)
 
// Step 2: Signature Fails
// ... SSH protocol loop continues ...
 
// Step 3: Attacker offers Own Key (Valid)
// The middleware now MUST ignore the context set in Step 1
 
// THE FIX:
// Instead of reading ctx.Value(proto.ContextKeyUser), 
// we look up the user based on the FINALLY VALIDATED key:
authenticatedUser, err := be.UserByPublicKey(mockCtx, s.PublicKey())

The developers also added a fingerprint check (pubkey-fp) to ensure the key used for authorization matches the key used for authentication. If they don't match, it's a dead giveaway of this exact bypass attempt.

The Exploit: Identity Theft in 4 Steps

Exploiting this requires a custom SSH client or a script, as standard clients like OpenSSH might not give you the granular control needed to force the "Offer-Fail-Offer-Pass" sequence in the exact order without disconnecting. However, writing a script using Python's paramiko or Go's golang.org/x/crypto/ssh is trivial.

The Attack Chain:

  1. Recon: You find a Soft Serve instance. You look up the admin's GitHub profile (often public) and grab their .keys (e.g., https://github.com/torvalds.keys). Now you have the Admin's public key.
  2. The Bait: Connect to the target SSH port. Send an SSH_MSG_USERAUTH_REQUEST offering the Admin's public key. The server sees the key, finds the Admin user in its DB, and sets Context.User = Admin.
  3. The Switch: The server asks for a signature. You send a dummy/invalid signature (or just move to the next key). The server rejects the key but keeps the session open for the next method.
  4. The Entry: You now send an SSH_MSG_USERAUTH_REQUEST with your own public key (which you previously registered as a normal user). You provide a valid signature. The server verifies it.

The Payoff: The server logic runs: "Okay, crypto checks out. Who is this session for? Oh, I see Context.User is set to Admin. Welcome back, boss!"

You now have full administrative access to the Git server. You can push malicious commits to protected branches, delete repositories, or modify server configurations if the TUI allows it.

The Impact: Why You Should Panic

This is a Critical severity issue (CVSS 8.1). In a Git server context, identity is everything.

  • Data Integrity: An attacker can overwrite history, inject backdoors into codebases, or delete critical data.
  • Confidentiality: If the server hosts private repositories, the attacker can clone them all.
  • Supply Chain Risk: If you use Soft Serve to host code that builds into production artifacts, an attacker can inject malicious code into your build pipeline without triggering standard "unauthorized push" alerts, because the push is authorized—as the Admin.

The vulnerability is particularly dangerous because it leaves very few logs. The SSH logs will show a failed auth attempt for the Admin (which looks like a typo) followed by a successful auth for the User. Unless you are correlating the internal session state with the auth logs, it looks like standard behavior.

The Fix: Remediation & Mitigation

The patch is straightforward but essential. You must upgrade Soft Serve to v0.11.3 or later immediately.

Remediation Steps

  1. Upgrade: Pull the latest docker image or update the binary.
    go install github.com/charmbracelet/soft-serve/cmd/soft@v0.11.3
  2. Audit: Check your Git logs. Look for commits made by administrators at unusual times or from IP addresses usually associated with lower-privilege users.
  3. Rotate Keys: If you suspect a breach, rotating keys is good practice, though this specific exploit doesn't steal private keys—it just impersonates the owner.

Developer Takeaway

For Go developers using charmbracelet/ssh or gliderlabs/ssh: Never store authorization state during the authentication handshake. The handshake is a volatile, untrusted zone. Only establish identity once the cryptographic handshake is fully complete and signed.

Official Patches

CharmbraceletCommit fixing the authentication middleware logic
CharmbraceletOfficial Security Advisory

Fix Analysis (1)

Technical Appendix

CVSS Score
8.1/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:U
EPSS Probability
0.17%
Top 62% most exploited

Affected Systems

Soft Serve <= 0.11.2

Affected Versions Detail

Product
Affected Versions
Fixed Version
Soft Serve
Charmbracelet
<= 0.11.20.11.3
AttributeDetail
CWE IDCWE-289
Attack VectorNetwork (SSH)
CVSS Score8.1 (Critical)
ImpactAuthentication Bypass / Privilege Escalation
Exploit StatusPoC Available (Regression Test)
Affected ComponentPublicKeyHandler / Wish Middleware

MITRE ATT&CK Mapping

T1078Valid Accounts
Defense Evasion
T1556Modify Authentication Process
Credential Access
CWE-289
Authentication Bypass by Alternate Name

Authentication Bypass by Alternate Name

Known Exploits & Detection

GitHub (Official Patch)Regression test case demonstrating the bypass via mock context

Vulnerability Timeline

Patch Committed
2026-01-21
Version 0.11.3 Released
2026-01-22
CVE-2026-24058 Published
2026-01-22

References & Sources

  • [1]GHSA-pchf-49fh-w34r Advisory
  • [2]NVD Entry for CVE-2026-24058
Related Vulnerabilities
CVE-2026-24058

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•CVE-2026-59213
3.5

CVE-2026-59213: Authorization Bypass and Cross-Session Cache Leakage in Open WebUI

An authorization bypass and cross-session cache leakage vulnerability exists in the model-listing backend of Open WebUI. The flaw stems from a configuration error in the @cached decorator of the aiocache library, which maps all unique user session queries to a single static cache key.

Alon Barad
Alon Barad
0 views•5 min read
•about 2 hours ago•CVE-2026-59215
3.1

CVE-2026-59215: Insecure Direct Object Reference in Open WebUI Thread Message Lookup

A Broken Object Level Authorization (BOLA) / Insecure Direct Object Reference (IDOR) vulnerability in Open WebUI prior to v0.10.0 allows authenticated users to access and disclose private message contents, thread context, and channel metadata from other restricted private or Direct Message (DM) channels without proper authorization.

Amit Schendel
Amit Schendel
4 views•6 min read
•about 3 hours ago•CVE-2026-59222
6.5

CVE-2026-59222: Sensitive Data Exposure in Open WebUI Channels API

Open WebUI versions starting from 0.7.0 up to, but excluding, 0.10.0 are vulnerable to a sensitive data exposure flaw in the channels API. The GET /api/v1/channels/{id}/members endpoint exposes full user database representations, including private API keys and webhook configurations. This allows authenticated users to extract private credentials of other members within the same channel.

Alon Barad
Alon Barad
5 views•4 min read
•about 4 hours ago•CVE-2026-59219
7.1

CVE-2026-59219: Session Revocation Bypass in Open WebUI Real-Time Endpoints

CVE-2026-59219 identifies a session-revocation bypass vulnerability in Open WebUI versions 0.9.0 through 0.9.99. While standard HTTP REST endpoints enforce stateful JWT revocation using a Redis-backed blacklist, WebSocket and Socket.IO endpoints bypassed these checks. Consequently, a token revoked via sign-out or OIDC logout remains valid for establishing real-time communication channels and accessing server terminal proxies.

Amit Schendel
Amit Schendel
5 views•6 min read
•about 5 hours ago•CVE-2026-59864
9.3

CVE-2026-59864: Critical Out-of-Package Local File Inclusion in Microsoft Kiota

CVE-2026-59864 is a critical path traversal vulnerability in Microsoft Kiota occurring when custom OpenAPI extensions specify a nested static template file. Lack of input sanitization allows malicious inputs to write directory traversal sequences directly into plugin manifests, causing out-of-package local file disclosure in downstream environments like Microsoft 365 Copilot.

Amit Schendel
Amit Schendel
6 views•7 min read
•about 20 hours ago•GHSA-X445-F3H2-J279
7.5

GHSA-X445-F3H2-J279: OAuth Provider Confusion in Auth.js and NextAuth.js

A critical logical security flaw exists in Auth.js (formerly NextAuth.js) where signed anti-CSRF check cookies (state, nonce, and PKCE code_verifier) are not bound to the specific Identity Provider that initiated the authorization flow. In multi-provider environments, this allows an attacker to replay valid, cryptographically signed cookies minted during a flow with one provider against a callback handling a different provider. This vulnerability can lead to session hijacking, identity theft, or unauthorized account linking.

Alon Barad
Alon Barad
7 views•7 min read