CVE-2026-48697: FastNetMon Sets Up TLS But Never Asks It to Verify Anything | Lorikeet Security Skip to main content
Back to Blog

CVE-2026-48697: FastNetMon Sets Up TLS But Never Asks It to Verify Anything

Lorikeet Security Team May 23, 2026 8 min read
CVSS 7.4 -- High

All Outbound HTTPS Connections Accept Any Certificate, Including Self-Signed — Telemetry Stream Is MITM-able

CVE
CVE-2026-48697
CVSS
7.4 (High)
CWE
CWE-295 (Improper Certificate Validation)
Affected
FastNetMon Community Edition <= 1.2.9
Component
src/fast_library.cpp, function execute_web_request_secure(), lines 1639-1670
Attack Vector
Remote (network-adjacent, MITM)
Discovered by
Lorikeet Security

FastNetMon sends periodic telemetry to community-stats.fastnetmon.com every 3600 seconds. The telemetry payload includes CPU model, kernel version, configured features, traffic statistics, and software version. The connection is HTTPS, set up via Boost.Asio's SSL context.

The TLS setup is incomplete in a way that is a well-known Boost.Asio footgun: the code creates an ssl::context in tls_client mode, calls set_default_verify_paths() to load the system's CA certificates, and sets the SNI hostname — but never calls set_verify_mode(ssl::verify_peer). The default verify mode for an Asio SSL context is verify_none. Without the verify_peer call, OpenSSL completes the handshake without checking that the certificate chain validates against the loaded CAs, that the hostname matches, or that the certificate hasn't expired or been revoked.

The net effect: any network attacker on the path between FastNetMon and community-stats.fastnetmon.com can intercept, read, and modify the telemetry stream by presenting any certificate they like. Self-signed certificates, expired certificates, certificates for the wrong hostname, certificates from any CA — all accepted.

Disclosure status: Lorikeet Security notified FastNetMon LTD on April 25, 2026. CVE-2026-48697 was assigned by MITRE. No vendor response or fix as of May 23, 2026.


The vulnerable code

// src/fast_library.cpp, execute_web_request_secure(), lines 1639-1670
boost::asio::ssl::context ctx(boost::asio::ssl::context::tls_client);
ctx.set_default_verify_paths();              // Loads system CA certificates.

// MISSING:
// ctx.set_verify_mode(boost::asio::ssl::verify_peer);
// ^^^ Without this, the default verify mode is verify_none.
//     The handshake completes regardless of certificate validity.

// SNI is set (which doesn't trigger verification):
SSL_set_tlsext_host_name(stream.native_handle(), host.c_str());

// Handshake proceeds with no verification:
stream.handshake(ssl_socket::client);

This is the canonical "I set up TLS but I forgot the verify call" bug. Boost.Asio's API design makes the bug easy to ship: set_default_verify_paths() sounds like it should also enable verification, but it doesn't — it just makes the CA certificates available for use if verification is enabled. Loading CAs without enabling verification is like installing a lock without ever locking the door.

The same shape appears in many other Boost.Asio-using projects. Static analyzers have specific rules for it (CodeQL's cpp/boost-network-no-verify-peer, Coverity's TLS misuse detector), and OpenSSL's own documentation warns about exactly this failure mode. The reason it keeps appearing is that the working-but-insecure case looks correct: the TLS handshake completes, the data flows, the operator sees green checkmarks in the logs. Nothing fails, and so nothing tells the developer that they missed a step.


What an attacker can do

An attacker on the network path between FastNetMon and community-stats.fastnetmon.com can:

Threat model: who has the necessary position?

The attacker needs to be on the network path between the FastNetMon host and the destination server. Realistic scenarios:

For most operators, the upstream ISP is the realistic threat. TLS is supposed to handle this; without certificate verification, it doesn't.


How a fix should look

boost::asio::ssl::context ctx(boost::asio::ssl::context::tls_client);
ctx.set_default_verify_paths();

// 1. Require certificate verification.
ctx.set_verify_mode(boost::asio::ssl::verify_peer);

// 2. Verify the hostname in the certificate matches the connection target.
ctx.set_verify_callback(boost::asio::ssl::host_name_verification(host));

// 3. (Defensive) Pin TLS minimum version.
ctx.set_options(boost::asio::ssl::context::default_workarounds
              | boost::asio::ssl::context::no_sslv2
              | boost::asio::ssl::context::no_sslv3
              | boost::asio::ssl::context::no_tlsv1
              | boost::asio::ssl::context::no_tlsv1_1);

// 4. (Optional but stronger) Pin the expected certificate or CA.
// For the telemetry endpoint where the destination is known and stable:
// ctx.load_verify_file("/etc/fastnetmon/community-stats-ca.crt");

// SNI as before:
SSL_set_tlsext_host_name(stream.native_handle(), host.c_str());

// Handshake now verifies the certificate against the loaded CAs and the hostname.
stream.handshake(ssl_socket::client);

Four steps. The first two are the minimum required — set_verify_mode turns verification on, and set_verify_callback with host_name_verification binds the verified certificate to the expected hostname. The third (TLS version pinning) and fourth (CA pinning) are defense-in-depth measures appropriate for a connection to a known, fixed destination.

For the telemetry use case specifically, certificate pinning makes sense. The destination is community-stats.fastnetmon.com, which is controlled by FastNetMon LTD and doesn't change. Pinning the CA (or the certificate's public key) means even a successful attack against a trusted CA (issuing a fraudulent certificate for the domain) doesn't compromise the telemetry channel. This is the same defensive technique used by major browsers' HSTS preload + HPKP setups, scaled down to a single-application client.


Compensating controls


The pattern: TLS APIs that fail open

Boost.Asio's SSL context defaulting to verify_none is a well-known API ergonomics issue. The library has chosen this default for backward compatibility — the API has been stable since Asio joined Boost in 2005, and changing the default would break every existing application that relies on the old behavior. So the unsafe default persists, and applications that follow the "obvious" setup path (create context, load CAs, handshake) end up with no verification.

Python's ssl module made the opposite choice in 2017 (PEP 543): the default SSLContext validates certificates. Most modern HTTP libraries (requests, httpx, libcurl) have the same default. The lesson is that defaults should fail closed, not fail open.

For Boost.Asio users specifically, the defensive coding pattern is to always pair the SSL context setup with an explicit set_verify_mode call. Make it a project linting rule: any ssl::context constructor invocation that isn't followed by a set_verify_mode(verify_peer) call somewhere in the same function should be a compile-time warning. This is a one-line change to a static analyzer's configuration and it catches every future instance of this bug.

For developers reviewing TLS code generally: "the TLS handshake succeeded" tells you nothing about whether the connection is secure. The handshake succeeding only means the cryptographic protocol completed without protocol-level errors. Certificate validation, hostname verification, and revocation checking are separate steps that have to be configured explicitly. If you're reading TLS setup code and you can't point to the specific lines that perform each of those three checks, the code is probably wrong.


Disclosure timeline

DateEvent
2026-04-25Vulnerability identified during Lorikeet Security source code audit of FastNetMon Community Edition 1.2.9
2026-04-25CVE ID requested from MITRE
2026-04-25Vendor (Pavel Odintsov / FastNetMon LTD) notified at the contact published in SECURITY.md
2026-05-22CVE-2026-48697 assigned by MITRE
TBDVendor response
TBDFix release
2026-05-23Lorikeet 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.

Download PDF

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.

-- views
Link copied!
Lorikeet Security

Lorikeet Security Team

Penetration Testing & Cybersecurity Consulting

Lorikeet Security helps modern engineering teams ship safer software. Our work spans web applications, APIs, cloud infrastructure, and AI-generated codebases — and everything we publish here comes from patterns we see in real client engagements.

Lory waving

Hi, I'm Lory! Need help finding the right service? Click to chat!