Feb 21, 2026·5 min read·27 visits
GoBGP versions before 3.35.0 crash if they receive a BGP OPEN message with a Software Version Capability length of 0. This is a classic Go slice bounds panic (low > high) exploitable remotely without authentication.
A critical denial-of-service vulnerability in GoBGP allows unauthenticated remote attackers to crash the BGP daemon by sending a malformed OPEN message. The flaw resides in the parsing logic for the Software Version Capability (RFC 9174), where a zero-length field triggers a Go runtime panic due to invalid slice bounds. This results in an immediate teardown of BGP sessions and potential network outages.
BGP (Border Gateway Protocol) is the duct tape holding the internet together. It relies on trust, keepalives, and the assumption that your peer isn't trying to murder your router process. GoBGP has emerged as a modern, high-performance alternative to legacy routing daemons like Quagga or FRR, written in Go to leverage memory safety and concurrency.
But memory safety doesn't mean logic safety. In CVE-2025-43971, we find a vulnerability that is almost poetic in its simplicity. It's not a complex heap overflow or a race condition. It is a simple disagreement between a developer's assumption and the Go runtime's strict rules on slicing. By sending a single byte set to 0x00 inside a specific BGP capability, an attacker can force the GoBGP process to commit suicide via panic(), tearing down all routing sessions instantly.
The vulnerability lies in how GoBGP handles RFC 9174, which defines the "Software Version Capability" (Type 71). This capability allows a BGP speaker to tell its peer what software version it's running (mostly for debugging or vanity). The structure is simple: a Type Code, a Length, and a Value string.
In the DecodeFromBytes function within pkg/packet/bgp/bgp.go, the code is responsible for taking the raw bytes of the capability and turning them into a struct. It reads the length byte to determine how long the version string is.
The fatal flaw? The code assumed that if the declared length wasn't too big (over 64 bytes), it was valid. It forgot to check if the length was too small (zero). In the world of C, this might have just resulted in an empty string or a pointer to nothing. In the world of Go, however, messing up slice indices is a capital offense punishable by immediate process termination.
Let's look at the vulnerable code in pkg/packet/bgp/bgp.go prior to version 3.35.0. The parser takes a byte slice data containing the capability payload.
// Vulnerable Code
softwareVersionLen := uint8(data[0]) // Read the length byte
// Check if we have enough data, or if length is absurdly large
if len(data[1:]) < int(softwareVersionLen) || softwareVersionLen > 64 {
return NewMessageError(...)
}
// THE CRASH SITE
c.SoftwareVersion = string(data[1:c.SoftwareVersionLen])Here is the logic trap:
data[0] is 0.softwareVersionLen becomes 0.len(data[1:]) < 0 is false. The check passes.data[1:0].In Go syntax slice[low : high], the rule is strict: low must be less than or equal to high. Here, we are asking for a slice starting at index 1 and ending at index 0. This is impossible.
The Result:
panic: runtime error: slice bounds out of range [1:0]
The fix was painfully simple: explicitly forbid zero lengths.
- if len(data[1:]) < int(softwareVersionLen) || softwareVersionLen > 64 {
+ if len(data[1:]) < int(softwareVersionLen) || softwareVersionLen > 64 || softwareVersionLen == 0 {Exploiting this does not require a complex fuzzing harness. It requires a basic BGP speaker implementation (like a Python script using Scapy or a small Go program). The attack vector is the BGP OPEN message, which is the very first message sent to establish a session.
The Attack Chain:
0x00.Because this happens during the OPEN phase, the attacker does not need to be fully established or authenticated if the router accepts connections from 0.0.0.0/0 (common in Route Server or public peering scenarios). Even if ACLs are in place, if the attacker can spoof a trusted IP (hard with TCP, but possible) or is a disgruntled peer, they can take down the router with a single packet.
In a web server, a panic might just restart a single goroutine or worker process. In GoBGP, this panic happens in the packet decoding path, often bubbling up to the main loop depending on how the supervisor is configured.
If the GoBGP binary crashes:
Since BGP implementations are expected to be robust, this is a high-severity Availability impact (CVSS 8.6).
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
GoBGP OSRG (Open Source Routing Gym) | < 3.35.0 | 3.35.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-193 (Off-by-one / Range Error) |
| CVSS v3.1 | 8.6 (High) |
| Attack Vector | Network (BGP OPEN Message) |
| Impact | Denial of Service (DoS) |
| EPSS Score | 0.00115 (~30%) |
| Exploit Status | Trivial PoC possible |
A product calculates or uses an incorrect maximum or minimum value that is 1 more, or 1 less, than the correct value.