BGP Extended-Length Attributes Silently Truncate to the Low Byte and Cascade Into Parse Confusion
- CVE
- CVE-2026-48685
- CVSS
- 6.5 (Medium)
- CWE
- CWE-130 (Improper Handling of Length Parameter Inconsistency)
- Affected
- FastNetMon Community Edition <= 1.2.9
- Component
- src/bgp_protocol.hpp, function
parse_raw_bgp_attribute(), line 173 - Attack Vector
- Remote (via BGP peer through GoBGP)
- Discovered by
- Lorikeet Security
RFC 4271 Section 4.3 defines BGP path attributes with a flexible length encoding. Every attribute carries a flags byte, and one of those bits — the Extended Length bit (0x10) — signals that the length field is two bytes (a 16-bit big-endian value) instead of one. The two-byte form is what BGP uses for attributes that need to carry more than 255 bytes, which includes most realistic AS_PATH attributes, large community lists, MP_REACH_NLRI with many prefixes, and BGP-LS attributes.
FastNetMon Community Edition does not implement its own BGP listener; it consumes BGP route data from an external GoBGP daemon. But the route data passes through FastNetMon's BGP attribute parser, parse_raw_bgp_attribute() in src/bgp_protocol.hpp. Lorikeet Security found that this parser correctly identifies when the Extended Length flag is set — it sets a local variable length_of_length_field = 2 — but then reads only a single byte for the attribute's value length, ignoring the second byte entirely.
Disclosure status: Lorikeet Security notified FastNetMon LTD on April 25, 2026. CVE-2026-48685 was assigned by MITRE. No vendor response or fix as of May 23, 2026.
The bug
// In parse_raw_bgp_attribute() -- src/bgp_protocol.hpp around line 173
if (attr_flags.extended_length_bit == 1) {
length_of_length_field = 2; // Correctly identifies 2-byte length
}
// ...
attribute_value_length = value[2]; // BUG: only reads 1 byte
// Should be:
// attribute_value_length = (value[2] << 8) | value[3];
Concrete example: a path attribute is sent with the Extended Length bit set and an actual value length of 300 bytes (encoded as the two bytes 0x01 0x2C). The parser reads only the first byte (0x01, decimal 1), sets attribute_value_length = 1, and proceeds to interpret the next 1 byte as the entire value of this attribute. The remaining 299 bytes — which were the rest of this attribute — are then interpreted as the start of the next attribute.
Or the inverse: a 44-byte attribute is encoded with Extended Length set and length bytes 0x00 0x2C. The parser reads only 0x00 as the length, interpreting the attribute as zero-length, and treats the actual 44-byte value as 44 attributes that start at offsets 0, 1, 2, .. through whatever flag/type combinations happen to land at those offsets. Cascading parse confusion follows for the rest of the UPDATE message.
What the cascading confusion produces
- Type confusion across attributes. The orphan bytes are parsed as if they were attribute headers. Their first byte gets read as flags (which determines whether the parser expects a 1-byte or 2-byte length next), their second byte gets read as the type code, and so on. Because the flags byte is a bitmap and the type byte is small integer, almost any byte sequence will "parse" without an obvious structural error.
- Length-field underflows. When the cascade lands on a high byte value being read as a 1-byte length, the parser then attempts to consume that many bytes from a buffer that has fewer than that many bytes remaining. The result depends on the next bounds check — if the surrounding code checks remaining-bytes, the message is rejected; if it relies on the inner parse function to bail, the OOB read happens before the outer code notices.
- Phantom attributes. The parser may emit BGP attributes — AS_PATH segments, communities, next-hops — that the originating peer never actually announced. Downstream code that trusts the parsed attribute list as a faithful representation of the announcement will make incorrect decisions based on those phantoms.
Why this is a Medium and not a High
The CVSS scoring (6.5 Medium) reflects two factors that constrain the impact:
- FastNetMon does not implement its own BGP listener. The bug is reachable only through an external GoBGP (or ExaBGP) daemon that already terminated the BGP session, did its own parsing, and re-emitted the attribute data into FastNetMon. The external speaker is a meaningful prefilter — GoBGP, in particular, is a robust BGP implementation that will reject malformed UPDATE messages before they ever reach FastNetMon. So the attacker needs to find an attribute encoding that GoBGP accepts as valid BGP but that FastNetMon then misparses. The set of such encodings is non-empty (any legal extended-length attribute longer than 255 bytes), but it's narrower than "send any garbage you want."
- The exploit primitive is parse confusion, not memory corruption. The most direct outcomes are denial of service (parse error stalls update processing) and incorrect routing decisions (phantom attributes drive incorrect mitigation behavior). True out-of-bounds reads can occur as a secondary effect of the cascade, but they require specific encodings that survive intermediate bounds checks elsewhere in the parser.
That said, "Medium" is not "negligible." A BGP peer that can influence the routing decisions of a DDoS mitigation engine has a meaningful position. The mitigation engine's job is to decide whether to install blackhole routes, and a phantom AS_PATH or community that causes a misjudgment can translate into operator-visible service impact.
How a fix should look
if (attr_flags.extended_length_bit == 1) {
length_of_length_field = 2;
attribute_value_length = (static_cast<uint16_t>(value[2]) << 8)
| static_cast<uint16_t>(value[3]);
} else {
length_of_length_field = 1;
attribute_value_length = value[2];
}
The fix is two lines. Make sure both lines actually execute — the bug here was a single-byte read where the surrounding code structure made it look like the two-byte case was handled, but the actual length-extraction statement after the flag check was the same one-byte read used by the non-extended path.
The defensive secondary improvement is to add an upper bound on attribute_value_length after extraction (BGP attributes max out at 65535 bytes by encoding, but a typical UPDATE message body is well under 4096 bytes, so any single attribute claiming >4096 should be treated as suspicious and probably malformed).
Compensating controls
- Constrain your BGP peer set. FastNetMon consumes BGP updates from a specific peer set you configure. Make sure that set is your own iBGP speakers or trusted upstreams, not arbitrary internet peers. Most operators already do this; if you don't, the BGP peer relationship is the entire attack surface for this CVE.
- Filter inbound BGP at GoBGP/ExaBGP. Strip attributes you do not consume (large communities you don't read, BGP-LS attributes if you only do unicast). Fewer attributes reaching the FastNetMon parser means fewer opportunities for the misparse to matter.
- Cap attribute lengths at the external speaker. GoBGP and ExaBGP can be configured to reject UPDATE messages with attribute lengths above a threshold. If you don't have a legitimate need for >255-byte attributes, a strict cap at 255 prevents the extended-length code path from being reached at all.
- Monitor BGP attribute parsing. FastNetMon's internal counters track parse errors; any sudden change in parse-error rate from a specific peer is a signal to investigate.
Why this kind of bug persists
The "read 1 of 2 length bytes" bug is one of the most-frequently-rediscovered parser bugs in networking history. It appears in BGP implementations, in TLS implementations (where it produces the OpenSSL extended-master-secret family of bugs), in DNS implementations (EDNS option lengths), in DHCP, in RADIUS attributes, in IKE payloads, and in dozens of other length-prefixed TLV encodings. The pattern is always the same: the protocol allows a length field to optionally widen from 1 byte to 2 (or 2 to 4), the code correctly detects the wider-length flag, but the actual integer-extraction statement doesn't get updated to read the wider field. The detection is visible to a code reviewer — you can see length_of_length_field = 2 right there — but the extraction statement is hidden in shorthand syntax that looks right at a glance.
The defensive coding pattern is to never use direct array indexing (value[2]) for length extraction. Use a read_uint8, read_uint16_be, read_uint32_be family of helpers that take an explicit bit-width argument, and force the choice of width to be an explicit decision at every call site. That way the call site itself contains the width, and the width has to match the flag check.
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-48685 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.