Integer Overflow in BGP AS_PATH Attribute Length — Heap Buffer Overflow on Encode
- CVE
- CVE-2026-48691
- CVSS
- 7.5 (High)
- CWE
- CWE-190 (Integer Overflow), CWE-122 (Heap-based Buffer Overflow)
- Affected
- FastNetMon Community Edition <= 1.2.9
- Component
- src/bgp_protocol.hpp, function
IPv4UnicastAnnounce::get_attributes(), lines 600-621 - Attack Vector
- Remote (via BGP peer through GoBGP or the gRPC API)
- Discovered by
- Lorikeet Security
Every other BGP CVE in this disclosure series is a parser bug. This one is an encoder bug, which makes it slightly different in shape. When FastNetMon needs to send a BGP UPDATE message — typically to announce a blackhole route via the gRPC API or to forward a route to its peers — it constructs the message in the IPv4UnicastAnnounce class. That class encodes path attributes into a dynamic_binary_buffer_t using attribute lengths that, for legacy reasons, are stored in a uint8_t field.
RFC 4271 explicitly allows BGP attribute lengths to be encoded in either 1 or 2 bytes (controlled by the Extended Length flag). The 2-byte form is required for any attribute longer than 255 bytes. FastNetMon's encoder uses a uint8_t for the length variable regardless of the actual size, which means the attribute_length value silently truncates the moment the actual attribute exceeds 255 bytes.
Disclosure status: Lorikeet Security notified FastNetMon LTD on April 25, 2026. CVE-2026-48691 was assigned by MITRE. No vendor response or fix as of May 23, 2026.
The vulnerable code
// src/bgp_protocol.hpp, IPv4UnicastAnnounce::get_attributes(), around line 600
uint8_t attribute_length = // <-- uint8_t holds up to 255
sizeof(bgp_as_path_segment_element_t) // = 2 bytes (segment header)
+ this->as_path_asns.size() * sizeof(uint32_t); // = 4 bytes per ASN
// For 64 ASNs: 2 + 64*4 = 258, which wraps to 2 (258 mod 256).
// Around line 615:
as_path_as_binary_array.set_maximum_buffer_size(as_path_attribute_full_length);
// Buffer sized to attribute_length-derived value — 2 bytes in this case.
// Around line 618:
for (auto& asn : this->as_path_asns) {
as_path_as_binary_array.append_uint32(asn); // <-- writes 4 bytes per call
}
// Total bytes written: 4 * 64 = 256 bytes. Buffer was sized for 2.
// Heap overflow of 254 bytes.
// Around line 621: same uint8_t truncation in path_segment_length.
The path-segment-length field at line 621 has the same shape: it's a uint8_t that holds the count of ASNs in a single AS_PATH segment. With more than 255 ASNs in a segment, the count wraps and the encoded BGP message contains a segment header whose length does not match the actual data that follows. Downstream BGP receivers may then misparse the message in interesting ways — some treat the truncated length as canonical and skip data they should have processed, others detect the mismatch and drop the session.
How an attacker reaches this
The encoder is invoked anywhere FastNetMon constructs a BGP UPDATE. The primary paths are:
- The gRPC API's
ExecuteBanmethod. When a ban is triggered (either by the detector or by an external caller invoking the gRPC API), FastNetMon announces a blackhole route via the configured BGP speaker. The route announcement passes throughIPv4UnicastAnnounce::get_attributes(), including the AS_PATH the announcement carries. If the AS_PATH is constructed from BGP path data received from peers and re-encoded for downstream announcements, an attacker who can inject a long AS_PATH from upstream (or who can call the gRPC API with a long AS_PATH parameter, see CVE-2026-48692) reaches the encoder. - BGP route forwarding. If FastNetMon is configured to receive routes from one BGP peer and announce them to another, the AS_PATH is concatenated as the route passes through. A long inbound AS_PATH gets re-encoded on outbound, triggering the overflow.
The gRPC API path is especially concerning because the API requires no authentication (CVE-2026-48692). An attacker who can connect to the gRPC port can invoke ExecuteBan with parameters that drive a long AS_PATH, triggering the encoder bug remotely.
The exploit shape
The overflow target is a dynamic_binary_buffer_t on the heap (the AS_PATH buffer). The overflow writes attacker-controlled ASN values past the buffer end into adjacent heap chunks. Each ASN is 4 bytes; the attacker can write up to 4 * (number_of_ASNs - 63) bytes past the buffer, with attacker-controlled values.
The values are not arbitrary bytes — they are 32-bit ASN values, which means the attacker chooses 4 bytes at a time and the values are interpreted by the receiver as ASNs. But the heap-overflow exploitation primitive doesn't care about value interpretation; only the bytes that get written matter. The attacker simply picks ASN values whose binary representation matches the bytes they want to write into adjacent heap memory.
For example, to write the 8 bytes 0xde 0xad 0xbe 0xef 0x41 0x41 0x41 0x41 past the buffer, the attacker requests an AS_PATH that ends with two extra ASNs whose 32-bit big-endian representations are 0xdeadbeef and 0x41414141 (in network byte order). The encoder writes those bytes verbatim past the buffer end. From there, the exploitation techniques are the same as for CVE-2026-48689 — corrupt heap metadata, achieve arbitrary write, escalate to code execution.
How a fix should look
// Use uint16_t for the attribute length and emit the Extended Length flag when needed.
uint16_t attribute_length =
sizeof(bgp_as_path_segment_element_t)
+ static_cast<uint16_t>(this->as_path_asns.size()) * sizeof(uint32_t);
bool need_extended_length = attribute_length > 255;
uint8_t attribute_flags = AS_PATH_BASE_FLAGS;
if (need_extended_length) {
attribute_flags |= EXTENDED_LENGTH_BIT;
}
// On wire, encode the length as 1 or 2 bytes depending on the flag.
if (need_extended_length) {
output.append_uint16_be(attribute_length);
} else {
output.append_uint8(static_cast<uint8_t>(attribute_length));
}
// Size the buffer based on attribute_length (now uint16_t) and copy all bytes.
as_path_as_binary_array.set_maximum_buffer_size(attribute_length);
// ... append all ASNs ...
The structural fix is to use uint16_t for any attribute length that might exceed 255 bytes, and to emit the Extended Length flag in the attribute flags byte when the length actually exceeds 255. This is what RFC 4271 specifies; FastNetMon's encoder was using a shorthand that only worked for short attributes.
The defensive secondary improvement is to add an explicit upper bound on the number of ASNs the encoder will accept. A typical AS_PATH has between 3 and 10 ASNs in production internet routing. Any AS_PATH with more than, say, 100 ASNs is either pathological or hostile and should be rejected at the encoder boundary with a useful log line.
Compensating controls
- Bind the gRPC API to localhost (which is the default) and ensure no other process on the host can reach it. The default bind is
127.0.0.1:50052, which prevents external attackers from invokingExecuteBanremotely. Verify yourfastnetmon.confdoes not override this. - Audit BGP peers for AS_PATH attribute size. Most legitimate AS_PATHs are short. GoBGP can be configured with policy rules that drop UPDATEs with abnormally long AS_PATHs before they reach FastNetMon.
- Use AS_PATH limit policies at your BGP edge. Many transit providers already drop AS_PATHs longer than 50–75 ASNs as a matter of policy. If your peer set includes such providers, your exposure is reduced.
- Run FastNetMon with heap hardening. Glibc's
GLIBC_TUNABLES=glibc.malloc.check=3at the environment level catches simple heap corruption atfreetime, converting some exploitable overflows into clean aborts. - Build with stack/heap protections. See the discussion in CVE-2026-48686. The same flags help here.
The pattern: the length field's type is the security boundary
This bug and CVE-2026-48690 share a root cause: the integer type used to hold a length value is too narrow for the values the program may actually compute. In CVE-2026-48690 it was unsigned int (32-bit) for a byte count that can naturally exceed 4GB. In this CVE it's uint8_t for an attribute length that can naturally exceed 255 bytes.
The pattern recurs because narrow integer types are tempting to use: they match the wire format exactly, they save a few bytes per object, and they "obviously" fit because the protocol field is that size. But the value being computed can exceed the field's wire-format width, and the truncation only manifests under specific conditions that are easy to miss in testing.
The defensive habit is to always compute lengths in the widest reasonable type (size_t or uint64_t), only narrow to the wire-format type at the moment of emission, and explicitly check the narrowing. The cost is one line of bounds check per encoder; the benefit is structurally eliminating this class of overflow. Every BGP-attribute encoder, every TLV serializer, every protocol marshaller should follow this pattern.
Disclosure timeline
| Date | Event |
|---|---|
| 2026-04-25 | Vulnerability identified during Lorikeet Security source code audit of FastNetMon Community Edition 1.2.9 |
| 2026-04-25 | CVE ID requested from MITRE |
| 2026-04-25 | Vendor (Pavel Odintsov / FastNetMon LTD) notified at the contact published in SECURITY.md |
| 2026-05-22 | CVE-2026-48691 assigned by MITRE |
| TBD | Vendor response |
| TBD | Fix release |
| 2026-05-23 | Lorikeet Security publishes responsible disclosure report |
Full Responsible Disclosure Report (PDF)
Complete writeup of all 16 FastNetMon Community Edition vulnerabilities Lorikeet Security identified, including vulnerable-code excerpts, impact analysis, and remediation guidance for each CVE.
Auditing the network infrastructure your business depends on
Lorikeet Security finds the parser bugs, protocol confusion, and unauthenticated-control-plane issues that move your DDoS detector, your BGP speaker, and your edge devices from "running" to "exploitable." Source code review, fuzz harness development, and adversarial protocol testing.