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



CVE-2026-23991
5.90.02%

Panic in the Supply Chain: Crashing TUF with Malformed JSON

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 15, 2026·6 min read·15 visits

PoC Available

Executive Summary (TL;DR)

The go-tuf library attempts to parse untrusted JSON metadata using unsafe Go type assertions. A malicious mirror can send syntactically valid but structurally incorrect JSON (e.g., wrong types for known fields), causing the client to panic and crash immediately. This creates a Denial of Service condition that prevents updates, reachable without authentication or signing keys.

A critical Denial of Service vulnerability exists in the go-tuf library, the Go implementation of The Update Framework (TUF). By serving malformed metadata JSON, a compromised repository mirror or Man-in-the-Middle attacker can trigger a runtime panic in the client. Crucially, this crash occurs during the parsing phase, before cryptographic signatures are verified, allowing an attacker without signing keys to disable the update mechanism across a fleet of devices.

The Hook: Trusting the Untrusted

The Update Framework (TUF) is the gold standard for software supply chain security. It’s the architectural equivalent of a paranoid bank vault, designed specifically to operate in hostile environments where repository mirrors might be compromised. The entire premise of TUF is: "We don't trust the mirror to tell the truth; we only trust the cryptographic signatures on the metadata."

But here is the irony: before you can verify a signature, you have to read the message. And if reading the message causes your brain to explode, the signature doesn't matter. That is exactly what happened in go-tuf.

This vulnerability isn't about stealing keys or injecting malware directly; it's about the fragility of code handling untrusted input. By exploiting a quirk in how Go handles interfaces, an attacker can turn a standard update check into a SIGABRT, effectively freezing a fleet of clients in time, unable to ever update again.

The Flaw: Go's Unforgiving Type Assertions

To understand this bug, you need to understand Go's type system. Go is statically typed, but it offers the interface{} (or any) type to handle dynamic data like JSON. When you unmarshal an arbitrary JSON blob, you often get a map[string]any.

To use that data, you have to tell Go what it is. "Trust me, compiler, this field is a string." In code, that looks like value.(string).

Here is the catch: If you are wrong—if value is actually an integer, or nil—Go doesn't just return an error. It panics. It flips the table and terminates the process immediately. This is a "Reachable Assertion" (CWE-617).

The developers of go-tuf wrote code that assumed the JSON structure coming from a mirror would always match the TUF specification. They chained these assertions together, walking through the JSON tree without a safety net. If a mirror sends a JSON object where the signed field is a string instead of a map, the application crashes hard.

The Code: A Chain of Assumptions

The vulnerability lived in metadata/metadata.go. The code was trying to determine the type of metadata (e.g., root, targets, snapshot) by inspecting the _type field inside the signed object.

Here is the smoking gun from the vulnerable version:

// The Vulnerable Code
// Assumption 1: "signed" exists and is a map
// Assumption 2: "_type" exists inside that map and is a string
signedType := m["signed"].(map[string]any)["_type"].(string)

Do you see the problem? It is a one-liner of doom. If m["signed"] is present but is actually a float, the first .(...) panics. If it is a map but _type is missing or is a boolean, the second .(...) panics.

The fix, introduced in version 2.3.1, replaces this cowboy coding with the "comma-ok" idiom, which is the standard, safe way to do type assertions in Go:

// The Fixed Code
// Check if "signed" is a map
signed, ok := m["signed"].(map[string]any)
if !ok {
    return &ErrValue{Msg: "metadata 'signed' field is missing or not an object"}
}
 
// Check if "_type" is a string
signedType, ok := signed["_type"].(string)
if !ok {
    return &ErrValue{Msg: "no _type found in signed"}
}

This change transforms a fatal crash into a manageable error that the client can log and ignore, allowing it to perhaps try a different mirror.

The Exploit: Crashing the Client

Exploiting this does not require a genius-level IQ or supercomputers. It requires a text editor. The attack vector is the repository mirror. In a real-world scenario, an attacker might compromise a CDN node, a mirror server, or perform a Man-in-the-Middle attack on HTTP traffic (since TUF is designed to work over plain HTTP, relying on signatures for security).

Here is the attack flow:

  1. Intercept: The victim client requests root.json from the mirror.
  2. Modify: The attacker intercepts the request and constructs a malicious JSON response.
  3. Payload: The attacker sends back valid JSON that violates the structural expectations.
{
  "signatures": [],
  "signed": "This should be a map, but I made it a string just to watch you cry."
}
  1. Crash: The go-tuf client receives this. It successfully unmarshals the JSON (because it is valid JSON). It then attempts m["signed"].(map[string]any). Since "signed" is a string, the runtime panics.

Because this check happens before signature verification, the attacker does not need any private keys. They just need to be in the network path.

The Impact: Denial of Service

At first glance, a crash sounds annoying but not catastrophic. In the context of an update framework, however, Availability is a security property.

If an attacker can crash the update client at will, they can enforce a "version freeze." Imagine a fleet of IoT devices with a known critical vulnerability (say, a remote root exploit). The vendor releases a patch. The devices wake up to download the patch.

The attacker, controlling a mirror or a specific network segment, serves the malformed JSON. Every single device crashes the moment it tries to update. The devices remain vulnerable to the root exploit indefinitely.

Furthermore, because the panic crashes the entire Go process, if the TUF client is integrated directly into a larger application (e.g., a microservice or a daemon) rather than running as a separate CLI tool, the entire application goes down. This escalates the issue from "cannot update" to "service outage."

The Fix: Remediation

The remediation is straightforward: update the library. The patch was released in version 2.3.1.

To patch your Go project:

go get github.com/theupdateframework/go-tuf@v2.3.1
go mod tidy

If you are a developer using go-tuf, you should also audit your own code for similar patterns. Search your codebase for direct type assertions (.(type)) on data that originates from external sources (user input, files, network requests). Always use the two-value assignment form (val, ok := x.(T)) to handle unexpected types gracefully without crashing the runtime.

Official Patches

GitHubCommit fixing the panic vulnerability

Fix Analysis (1)

Technical Appendix

CVSS Score
5.9/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.02%
Top 95% most exploited

Affected Systems

theupdateframework/go-tuf (< 2.3.1)Go applications embedding go-tuf for auto-updatesContainer image signing tools relying on older go-tuf versions

Affected Versions Detail

Product
Affected Versions
Fixed Version
go-tuf
theupdateframework
>= 2.0.0, < 2.3.12.3.1
AttributeDetail
CWE IDCWE-617 (Reachable Assertion)
Attack VectorNetwork (Mirror/MitM)
CVSS v3.15.9 (Medium)
EPSS Score0.02%
ImpactDenial of Service (DoS)
Exploit StatusTrivial (PoC available in unit tests)
LanguageGo

MITRE ATT&CK Mapping

T1499.004Endpoint Denial of Service: Application Exhaustion Flood
Impact
T1195.002Supply Chain Compromise: Compromise Software Supply Chain
Initial Access
CWE-617
Reachable Assertion

Reachable Assertion

Known Exploits & Detection

Unit TestsFunctional PoC included in the fix commit tests

Vulnerability Timeline

Fix committed to GitHub
2026-01-19
GHSA Advisory Published
2026-01-21
CVE Assigned
2026-01-22

References & Sources

  • [1]GHSA-846p-jg2w-w324 Advisory
  • [2]Go Vulnerability Database Entry

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.