Go JOSE is a popular Go library that makes dealing with JWT, JWE, and JWS standards easy and safe. However, if you are using version 4.x before 4..5, you might be vulnerable to a simple but critical Denial of Service (DoS) attack. This post breaks down what went wrong, how the vulnerability works, how to patch it, and how you might work around the problem if you can't upgrade right away.
What is Go JOSE?
Go JOSE (GitHub repo) is a Go implementation for handling JSON Web Encryption (JWE), JSON Web Signature (JWS), and JSON Web Token (JWT) payloads. It’s widely used in Go projects to handle secure token-based authentication, encryption, and signing.
The Bug: Why Version 4.x < 4..5 Is Vulnerable
The issue lies in how Go JOSE versions in the 4.x series before 4..5 split compact JWT and JWE inputs. Here’s what typically happens when parsing a JWT:
parts := strings.Split(token, ".")
Normally, JWTs use two or three dots (.) to separate sections (for example: header.payload.signature). But strings.Split will break the string at every dot, producing a slice as large as the number of dots + 1. This behavior isn't normally an issue, but:
What if the Input is Malicious?
An attacker can send a huge string that is mainly thousands (or millions) of . characters. This would create a massive Go slice (an array-like structure), which could:
Here's a simple way to imagine the attack
// Malicious JWT: a string with millions of dots
maliciousToken := strings.Repeat(".", 5_000_000)
// This will try to split it into 5,000,001 empty parts!
parts := strings.Split(maliciousToken, ".")
// parts now consumes massive memory, potentially killing the process
Exploit Scenario
1. Attacker sends specially crafted JWT/JWE tokens with excessive ., e.g., when authenticating to an API.
Vulnerable server (using affected versions of Go JOSE) receives the token and tries to parse it.
3. strings.Split blows up memory allocation for the giant array/slice.
The server process is killed or stalls, leading to Denial of Service.
No authentication or special privileges required—the attacker only needs the ability to send HTTP requests with tokens.
Fix: Upgrade to Go JOSE 4..5
The Go JOSE maintainers patched this in v4..5 release.
Safer splitting strategy in new code
The patch changes how tokens are split, only breaking input up to the expected number of segments (not every dot it sees). Here’s a safe example:
// Only split into the expected number of parts, e.g., 3 for a JWS token
parts := strings.SplitN(token, ".", 3)
This prevents excessive memory allocation, even if there are a lot of . characters.
Workaround: Pre-Validate Dots
If you cannot upgrade immediately, you can filter tokens before handing them to Go JOSE.
const MaxJWTSections = 3 // 2 dots for JWS
func isValidJWT(token string) bool {
count := strings.Count(token, ".")
return count == MaxJWTSections - 1 // For 3 parts, expect 2 dots
}
For a compact JWS/JWT, you should only see two dots (header, payload, signature). For JWE, four dots. Reject any input with too many dots!
References
- Original advisory on GitHub (update the link with the real advisory when available)
- Go JOSE Changelog
- CVE Page for CVE-2025-27144 (update with actual CVE page)
`
go get github.com/square/go-jose/v4@v4..5
`
2. If you cannot upgrade: Add an input wrapper to limit dots in any JWT/JWS/JWE input.
Summary
CVE-2025-27144 is a classic example of how simple things—like string splitting—can create serious security risks. If you use Go JOSE, patch immediately and validate your JWT inputs. Otherwise, any attacker could easily take down your service with a few HTTP requests.
Timeline
Published on: 02/24/2025 23:15:11 UTC