On 21 October 2026 Apache bRPC disclosed 35 vulnerabilities, 16 rated high and 19 moderate, all fixed in bRPC 1.18.0. The headline issue, CVE-2026-48830, lets an authentication decision leak across requests on one HTTP keep-alive connection. Every version through 1.17.0 is affected. Upgrade to 1.18.0 or apply the listed patches. No exploitation is reported.
This is a vulnerability disclosure, not a breach. As of the CISA Known Exploited Vulnerabilities catalog release of 23 October 2026 (version 2026.10.23), no bRPC CVE is listed. NVD had placed CVE-2026-48830 in "Deferred" status with no score of its own, and CISA's vulnerability enrichment for three of the 35 records says "Exploitation: none". We found no public proof of concept, and we are not going to describe one.
Two things make this batch matter. The fix for the headline bug was merged on 25 May 2026 and shipped in 1.18.0 on 17 September, five weeks before the CVEs went public on 21 October. And bRPC is a C++ library usually compiled in from source, so the lockfile based scanning most teams rely on often cannot see it.
What happened
Weibing Wang, a member of the bRPC project management committee, sent a single advisory covering all 35 issues to the oss-security list at 10:58 China Standard Time on 21 October (02:58 UTC), and to the Apache announce@apache.org list two minutes later. The subject line of both was "Apache bRPC security advisory: 35 vulnerabilities fixed in 1.18.0". The Apache Software Foundation, as the CVE Numbering Authority, published the 35 CVE records between 11:30 and 12:19 UTC the same day.
bRPC started life inside Baidu and became an Apache top level project. It is an embeddable RPC framework: applications link libbrpc and run brpc::Server in their own process, and one port can speak many protocols at once, chosen by sniffing the first bytes of each connection. The project's threat model lists baidu_std, HTTP/1.x, HTTP/2 and gRPC, Thrift, Redis, memcached, RTMP, Mongo and the nshead family among them, plus a set of HTTP "builtin services" such as /status, /vars, /flags, /connections, /rpcz and /health for operators.
That design explains the advisory: most of the 35 bugs sit in parsers that run before authentication, and several sit in the logic deciding which protocols and builtin services a port may reach.
The advisory at a glance
| Measure | Value | Source |
|---|---|---|
| CVEs | 35 | Apache advisory |
| Rated high | 16 | Apache advisory |
| Rated moderate or medium | 19 | Apache advisory |
| Affected | "through 1.17.0" for 34 CVEs; 1.11.0 through 1.17.0 for CVE-2026-79704 | Apache advisory |
| Fixed | 1.18.0, or the per CVE pull request | Apache advisory |
| CVSS from the project | None; Apache publishes word ratings only | Apache advisory |
| CVSS from CISA enrichment | 7.5 for CVE-2026-56386 and CVE-2026-82230; 5.4 for CVE-2026-84727 | CVE records, CISA ADP container |
| Known exploitation | None reported; not in KEV 2026.10.23 | CISA KEV, CVE records |
Timeline
All times are UTC unless stated.
| Date and time | Event | Source |
|---|---|---|
| 20 May 2026 | bRPC PMC confirms the scope for a threat model drafted by the ASF Security Team | bRPC THREAT_MODEL.md |
| 24 May 2026, 07:41 | CVE-2026-48830 reserved by Apache | CVE record |
| 24 May 2026, 08:45 | Pull request 3308, "apply auth check to builtin requests on public port", opened | GitHub PR 3308 |
| 25 May 2026 | PR 3308 merged into master as merge commit a47e349 | GitHub PR 3308 |
| 28 May 2026, 14:21 | bRPC 1.17.0 released; the advisory lists it as affected | GitHub releases |
| 14 Jun to 12 Sep 2026 | The other 34 CVE IDs reserved in batches | CVE records |
| 17 Sep 2026, 15:53:36 | bRPC 1.18.0 published on GitHub with all fixes | GitHub release 1.18.0 |
| 21 Oct 2026, 02:58:40 | Advisory posted to oss-security (10:58:40 +0800) | openwall.com |
| 21 Oct 2026, 03:00:16 | Same advisory to announce@apache.org | lists.apache.org |
| 21 Oct 2026, 11:30 to 12:19 | 35 CVE records published | cve.org |
| 21 Oct 2026, 12:17 | NVD receives CVE-2026-48830, status later shown as Deferred | NVD API |
| 21 Oct 2026, 13:07 to 15:11 | CISA enrichment added to three records, each "Exploitation: none" | CVE records |
| 23 Oct 2026, 19:30 | CISA KEV catalog 2026.10.23 released; no bRPC entries | CISA KEV feed |
Holding CVE publication until a release has spread is normal practice. The point for defenders is that the fixed code sat in a tagged release for 34 days before anyone outside the project was told it mattered.
Who is affected
You are affected if you build or ship anything that links bRPC 1.17.0 or earlier. Whether a specific CVE is reachable depends on which bRPC features your service turns on. The table maps features to the CVEs that need them.
| If your service | CVEs that apply |
|---|---|
Sets ServerOptions.auth and leaves builtin services on the public port | CVE-2026-48830 (high) |
Sets both ServerOptions.auth and ServerOptions.internal_port | CVE-2026-86249 |
Sets internal_port and enables any protobuf protocol on the public port | CVE-2026-84748 |
| Sits behind a proxy that enforces path ACLs | CVE-2026-84747, CVE-2026-86146 |
Exposes builtin services (/flags, /pprof) to untrusted networks | CVE-2026-86147 |
| Serves streaming RPC with an Authenticator | CVE-2026-78334, plus 80463, 81755, 82210 |
| Accepts HTTP/2 or gRPC (the h2 parser is on by default) | CVE-2026-54425, 56386, 78048, 78058 (all high), 61902 |
| Runs a Redis protocol server | CVE-2026-56388, 58064 (high) |
| Runs RTMP | CVE-2026-54427, 56387, 74758, 82953 (high), 84727 |
| Uses the nshead, ubrpc or mcpack2pb paths | CVE-2026-74757, 82230 (high), 74755 |
| Accepts compressed bodies, sofa-pbrpc, RTMP or mcpack2pb | CVE-2026-78066 (high) |
Runs on ARM64 or another platform where plain char is unsigned | CVE-2026-61916 |
| Uses bRPC as a client of Redis, Thrift, MySQL, Discovery or multi-stream servers | CVE-2026-54426, 82231 (high), 90484, 87849, 79704 |
| Uses client TLS and relies on certificate verification | CVE-2026-66392 |
| Uses client health checks | CVE-2026-82425 |
| Is built with RDMA | CVE-2026-82942 |
Services with authentication enabled should pay the most attention: several of these CVEs show ways the Authenticator could be bypassed. Services that only act as clients are also in scope.
Where bRPC hides
bRPC is usually fetched as a source tarball, added as a CMake or Bazel dependency, or vendored. Places to look:
- Your own C++ services. Anything that includes
brpc/server.horbrpc/channel.h. - Databases and analytics engines that vendor it. On 24 October the master branch build scripts of Apache Doris and StarRocks referenced bRPC 1.4.0 and 1.9.0. Either may patch or disable the affected features, and neither had published a statement we could find. Check them; do not assume exposure.
- Package managers for C++. The vcpkg
brpcport reads 1.18.0, but a pinned baseline will not pick it up. - Container images. A static
libbrpc.aleaves nodpkgorrpmentry for image scanners to read.
Customised forks, which the project's case list shows are common, get no upstream release; someone has to port the patches.
How the issues work
This section explains the root causes at the level a defender needs to judge exposure. It does not give request sequences, and you do not need them to decide whether to patch.
CVE-2026-48830: an authentication decision that stuck to the connection
bRPC's Authenticator runs once per connection, on the first message, not on every request. The project documents this. Its threat model lists "Authenticator::VerifyCredential runs once per connection, not once per request" as a false friend property, and names treating it as per request authentication as a common misuse.
Separately, builtin services were handled differently from business endpoints when they arrived on the public listener. According to the advisory, if a builtin HTTP request was the first message on a socket, the connection could be marked as authenticated, and later requests on the same HTTP/1.1 keep-alive connection to protected, non-builtin endpoints were then served without the credential check. The conditions are both of these:
ServerOptions.authis set, so the operator intended authentication.- Builtin HTTP services are reachable on the public listener, which is the default unless
internal_portis set orhas_builtin_servicesis false.
The fix in PR 3308 makes builtin HTTP requests arriving on the public port go through the same authentication as everything else. The pull request flags this as a breaking change: if you relied on unauthenticated access to /status or /vars on the public port of an authenticated server, that access now fails. Builtin requests on internal_port still skip authentication by design, which is why the next two CVEs mattered.
The finder is credited as Brubbish of VARAS@IIE.
CVE-2026-86249 and CVE-2026-84748: when internal_port was not the boundary it looked like
The documented way to keep builtin services away from the internet is to set ServerOptions.internal_port to a port only internal hosts can reach. Two CVEs show that, before 1.18.0, this was not a complete boundary.
- CVE-2026-86249 affects servers that set both
authandinternal_port. Builtin requests on the internal port are exempt from authentication by design, but ordinary services were also served there. Because the verdict latches per connection, the same carry over effect as CVE-2026-48830 applied on the internal port: an unauthenticated connection could end up reaching ordinary authenticated services. The fix restrictsinternal_portso it carries only builtin and Tabbed services and rejects ordinary services with HTTP 403. If you sent business traffic to the internal port, you must move it to the port passed toServer::Start(). - CVE-2026-84748 is about protocols other than HTTP. The HTTP and h2 paths enforced the internal port rule, but the protobuf based protocols (
baidu_std,hulu_pbrpc,sofa_pbrpc, and the nshead family such aspublic_pbrpc,nshead_mcpack,nova_pbrpcandubrpc2pb) computed a security mode flag and never enforced it. Builtin services share the method map with user services, so a client on the public port could call builtin services such asbrpc.varsorhotspotsby name, disclosing metrics, flags and profiler data.
The practical lesson is that, on 1.17.0 and earlier, setting internal_port was necessary but not sufficient. A firewall rule that keeps the internal port off untrusted networks, and a separate check that the public port cannot reach builtin services over any protocol, were both needed.
Other access control and trust bugs
- CVE-2026-84747, empty path segments. The HTTP dispatcher collapsed consecutive slashes, so a proxy that blocks builtin paths by exact match could be walked around, and HTTP/2
:pathvalues were not validated. Such paths are now rejected unless-http_allow_empty_path_segmentsis set, which the advisory advises against on exposed servers. - CVE-2026-86146, HTTP/1.1 parsing differences. bRPC accepted header forms a strict proxy rejects or reads differently, including spaces around framing values, obsolete line folding and chunked trailers merged into the header map. Behind a proxy this allows request smuggling and smuggled
AuthorizationorX-Forwarded-Forheaders. The fix rejects those forms and drops trailers;http_allow_obs_foldandhttp_strict_header_tokenadjust the behaviour. - CVE-2026-86147,
/flagsand/pprof. Where builtin services are reachable,/flagscould change the dump path gflags (bvar_dump_file,bvar_dump_tabs,mbvar_dump_file) so the process created directories and truncated files with its own privileges, and/pprofhad no duration cap. Those flags are now frozen at runtime and/pprofis capped by-max_profiling_seconds(default 300). This is why the bRPC docs say never to run it as root. - CVE-2026-78334, streaming frames. Streaming RPC frames bypassed the authentication hook, and a stream could accept frames from a different socket carrying its ID. Both are now rejected.
- CVE-2026-66392, TLS peer names. The client checked the certificate chain but not the name, so any certificate from a trusted CA could impersonate the server. After upgrading, enable
VERIFY_PEERwith a positiveverify_depth, and setVerifyOptions::expected_peer_namewhere the name differs from the URL host.verify_depth=0means verification is off.
The parser cluster: crashes before authentication
Most of the remaining CVEs are parser bugs that a remote peer can reach before any application code runs. The threat model says the h2 parser "runs before any Authenticator check on the shared port", and the Redis, RTMP and mcpack paths behave the same way.
- Memory corruption. CVE-2026-56388 is an out of bounds write in the Redis command parser, guarded only by a
CHECKthat does not abort in every build. CVE-2026-74758 and CVE-2026-84727 are use after free bugs triggered by RTMP Abort messages. - Out of bounds reads. CVE-2026-56386 is an underflow in the HTTP/2 DATA handler for a zero length padded frame. CVE-2026-61916 hits only platforms where plain
charis unsigned, such as ARM64; typical x86_64 builds are not affected. - Recursion and assertions. CVE-2026-54425, 54426, 54427 and 82230 let nesting exhaust the stack; the fixes add iterative parsing or a depth limit of 128. CVE-2026-78048 is an HPACK table sized for a 34 byte minimum entry where RFC 7541 allows 33, so a full table hits a
CHECK. - Resource exhaustion. CVE-2026-78058 covers missing HTTP/2 limits on streams, decoded header size and control frame acknowledgements. CVE-2026-78066 covers uncapped decompression and trusted length fields in several protocols.
Eight CVEs are client side: a malicious server, or anyone on the network path, can crash or mislead a bRPC client through Redis, Thrift, MySQL, Discovery or multi stream replies, the TLS name check, health checks or the h2 client limits. Services that only call other services still need the upgrade.
Technical details
All values below come from the Apache advisory as posted to oss-security and the Apache announce list, the CVE records on cve.org, and the bRPC 1.18.0 release notes.
All 35 CVEs: severity, weakness, affected and fixed versions, patch
Every row is fixed in 1.18.0. "Affected" is the advisory's range; "PR" is the patch the advisory names for teams that cannot take the full release.
| CVE | Apache rating | Title (shortened) | CWE | Affected | PR |
|---|---|---|---|---|---|
| CVE-2026-48830 | High | Builtin HTTP request can mark a connection authenticated | CWE-287 | through 1.17.0 | 3308 |
| CVE-2026-54425 | High | Stack exhaustion via recursive HPACK table size updates | CWE-674 | through 1.17.0 | 3343 |
| CVE-2026-54426 | High | Stack exhaustion in Redis reply parser (client) | CWE-674 | through 1.17.0 | 3344 |
| CVE-2026-54427 | High | Stack exhaustion in AMF parser (RTMP) | CWE-674 | through 1.17.0 | 3344 |
| CVE-2026-56386 | High | Integer underflow and OOB read in HTTP/2 DATA parser | CWE-191, CWE-125 | through 1.17.0 | 3325 |
| CVE-2026-56387 | High | Memory exhaustion in RTMP AMF parser | CWE-789, CWE-770 | through 1.17.0 | 3353 |
| CVE-2026-56388 | High | Out of bounds write in Redis command parser | CWE-787, CWE-617, CWE-252 | through 1.17.0 | 3354 |
| CVE-2026-58064 | High | Unbounded Redis inline command allocation | CWE-770 | through 1.17.0 | 3363 |
| CVE-2026-61902 | Medium | Inconsistent message body limits | CWE-400 | through 1.17.0 | 3382 |
| CVE-2026-61916 | Moderate | OOB read in lookup tables on unsigned char platforms | CWE-125 | through 1.17.0 | 3376 |
| CVE-2026-66392 | Medium | TLS client accepts certificates for mismatched names | CWE-297 | through 1.17.0 | 3408 |
| CVE-2026-74755 | Moderate | Integer underflow in mcpack2pb parser | CWE-191 | through 1.17.0 | 3450 |
| CVE-2026-74757 | High | Uncontrolled allocation via mcpack array item count | CWE-770 | through 1.17.0 | 3451 |
| CVE-2026-74758 | High | Heap use after free in RTMP Abort handling | CWE-416 | through 1.17.0 | 3452 |
| CVE-2026-78048 | High | HPACK dynamic table sizing assertion | CWE-617 | through 1.17.0 | 3462 |
| CVE-2026-78058 | High | Unbounded resources and crash in HTTP/2 receive path | CWE-400, CWE-476 | through 1.17.0 | 3474 |
| CVE-2026-78066 | High | Unbounded decompression and wire declared sizes | CWE-770 | through 1.17.0 | 3476 |
| CVE-2026-78334 | Medium | Missing authentication for streaming RPC frames | CWE-306 | through 1.17.0 | 3481 |
| CVE-2026-79704 | Medium | OOB read in multi stream RPC response (client) | CWE-125 | 1.11.0 through 1.17.0 | 3485 |
| CVE-2026-80463 | Medium | Unbounded stream message reassembly | CWE-770 | through 1.17.0 | 3489 |
| CVE-2026-81755 | Medium | Excessive streams in a single RPC | CWE-400 | through 1.17.0 | 3493 |
| CVE-2026-82210 | Medium | Crash via malformed stream feedback frames | CWE-617 | through 1.17.0 | 3494 |
| CVE-2026-82230 | High | Stack exhaustion in mcpack2pb parser | CWE-674 | through 1.17.0 | 3499 |
| CVE-2026-82231 | High | Malformed Thrift T_EXCEPTION reply terminates client | CWE-248 | through 1.17.0 | 3500 |
| CVE-2026-82425 | Moderate | Reachable assertion in Socket::OnInputEvent | CWE-617 | through 1.17.0 | 3510 |
| CVE-2026-82942 | Moderate | Race on shared input buffer in RDMA transport | CWE-362 | through 1.17.0 | 3505 |
| CVE-2026-82953 | High | NULL dereference in RTMP createStream error path | CWE-476 | through 1.17.0 | 3508 |
| CVE-2026-84727 | Moderate | Use after free in RTMP chunk stream via Abort | CWE-416 | through 1.17.0 | 3515 |
| CVE-2026-84747 | Moderate | Access control bypass via empty path segments | CWE-436 | through 1.17.0 | 3512 |
| CVE-2026-84748 | Moderate | Builtin services reachable on public port via pb protocols | CWE-285 | through 1.17.0 | 3511 |
| CVE-2026-86146 | Moderate | HTTP request smuggling and header injection | CWE-444 | through 1.17.0 | 3521 |
| CVE-2026-86147 | Moderate | File creation via /flags, unbounded /pprof duration | CWE-73, CWE-400 | through 1.17.0 | 3523 |
| CVE-2026-86249 | Moderate | Auth bypass with internal_port plus auth | CWE-287 | through 1.17.0 | 3525 |
| CVE-2026-87849 | Moderate | OOB read in Discovery naming service reply parsing | CWE-125 | through 1.17.0 | 3533 |
| CVE-2026-90484 | Moderate | NULL dereference in MySQL reply parser (client) | CWE-476 | through 1.17.0 | 3536 |
One record oddity: the machine readable version field in the CVE record for CVE-2026-90484 reads <= 1.11.0 with an upper bound of "less than 1.18.0", while the advisory text says "through 1.17.0". Use the advisory text; any version before 1.18.0 should be treated as affected.
Scores and enrichment
Apache publishes word ratings only, and the CVE records carry no CNA CVSS vector. Any numeric score you see came from someone else. As of 24 October, CISA's enrichment container on three records gave:
| CVE | CISA CVSS 3.1 | Vector | SSVC |
|---|---|---|---|
| CVE-2026-56386 | 7.5 | AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H | Exploitation none, Automatable no, Technical impact partial |
| CVE-2026-82230 | 7.5 | AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H | Exploitation none, Automatable yes, Technical impact partial |
| CVE-2026-84727 | 5.4 | AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L | Exploitation none, Automatable no, Technical impact partial |
NVD showed CVE-2026-48830 as "Deferred" with no NVD metrics. Do not wait for an NVD score before acting; for this batch it may never come.
New limits and flags after upgrading
1.18.0 changes behaviour. Most changes reject traffic that was already malformed, but a few can reject deep or large legitimate payloads, so check them before rolling out.
| Setting | Default after 1.18.0 | Linked CVE | What it does |
|---|---|---|---|
redis_max_reply_depth | 128 | CVE-2026-54426 | Rejects deeper Redis reply nesting |
amf_max_depth | 128 | CVE-2026-54427 | Rejects deeper AMF nesting |
amf_max_string_size | 64 MiB | CVE-2026-56387 | Caps AMF string length |
amf_max_array_size | 1,048,576 elements | CVE-2026-56387 | Caps AMF array count |
redis_max_allocation_size | now applied to inline commands | CVE-2026-58064 | Caps inline command lines |
max_body_size | 64 MiB, now enforced consistently | CVE-2026-61902, 80463 | HTTP/1 returns 413; h2 streams reset |
max_decompressed_body_size | new flag | CVE-2026-78066 | Caps decompressed output |
max_concurrent_streams | 1024 per connection | CVE-2026-78058 | h2 stream cap; 4294967295 restores unlimited |
max_header_list_size | 1 MiB decoded per stream | CVE-2026-78058 | h2 header cap; h2_client_max_header_list_size for clients |
h2_ack_ignore_eovercrowded | off | CVE-2026-78058 | Restores the old acknowledgement behaviour if set |
stream_max_streams_per_request | 64 | CVE-2026-81755 | Caps streams declared in one RPC |
mcpack2pb MAX_DEPTH | 128 on parse path | CVE-2026-82230 | Matches the serializer's limit |
max_profiling_seconds | 300 | CVE-2026-86147 | Now also caps /pprof |
http_allow_empty_path_segments | off | CVE-2026-84747 | Restores doubled slash dispatch; not recommended |
http_allow_obs_fold | off | CVE-2026-86146 | Restores folded framing headers |
http_strict_header_token | off | CVE-2026-86146 | Optionally rejects spaces in any header name |
VerifyOptions::expected_peer_name | new | CVE-2026-66392 | Sets the name the server certificate must carry |
Two other behaviour changes come from the fixes rather than a flag. Ordinary services are no longer served on internal_port (CVE-2026-86249), and builtin HTTP requests on the public port of an authenticated server now need credentials (CVE-2026-48830). The release notes also say 1.18.0 aligns all builds on a C++14 baseline, so very old toolchains may need attention.
The release and its contents
The GitHub release for 1.18.0 is dated 2026-09-17T15:53:36Z; the RELEASE_VERSION file and set(BRPC_VERSION 1.18.0) in CMakeLists.txt both read 1.18.0. The release notes list the security fixes under "Bugfixes" and "Enhancements" without CVE IDs, for example "Apply auth check to builtin requests on public port" (PR 3308). Wording like "auth", "bound", "limit" and "reject" in release notes is a useful early signal. The same release added THREAT_MODEL.md and SECURITY.md (PR 3324); the threat model lists the defaults the project leaves to operators, including builtin services on the main port and client TLS verification off by default.
Credits
Counting each name once, the advisory credits 12 finders or teams. Fifteen CVEs, including CVE-2026-86249, 84748, 84747 and 86146, are credited to a finder listed only as "Claude", with no detail on who ran the analysis. Others include Brubbish of VARAS@IIE (CVE-2026-48830), Nikko Enggaliano Pratama (four), Feng Zhijie (three), Kaixuan Li and Ubeddulla Khan (two each), and a security vendor's research lab (two). CVE-2026-54427 and CVE-2026-84727 carry no credit.
Indicators of compromise
None were published. These are flaws, not a campaign. The closest thing to a signal is behaviour: unexpected process aborts with CHECK failures in HPACK, stream or socket code; requests to builtin paths such as /flags, /pprof, /vars or /hotspots from outside your operations network; and doubled slashes in request paths at your proxy. None of these proves an attack.
What to do now
1. Find every bRPC you build
Search source trees and build files, not lockfiles:
# Build definitions that pull bRPC
grep -rIn --include=CMakeLists.txt --include='*.cmake' --include=BUILD \
--include=BUILD.bazel --include=WORKSPACE --include=MODULE.bazel \
--include=vcpkg.json --include=conanfile.txt --include=conanfile.py \
--include='*.sh' -i 'brpc' .
# Code that includes it
grep -rIl --include='*.h' --include='*.hpp' --include='*.cc' --include='*.cpp' \
'#include [<"]brpc/' . | head
# Vendored copies carry their version in the tree
find . -path '*brpc*' \( -name RELEASE_VERSION -o -name CMakeLists.txt \) \
-exec grep -H -E '^1\.[0-9]+\.[0-9]+$|set\(BRPC_VERSION' {} \;
For vcpkg, run vcpkg list brpc and check the baseline in vcpkg-configuration.json. For a third party script that downloads a tarball, the version is usually in the URL, as in the Doris and StarRocks vars.sh files.
2. Find bRPC in binaries and images
# Shared or static libraries on a host or in an unpacked image
find / -xdev \( -name 'libbrpc*.so*' -o -name 'libbrpc*.a' \) 2>/dev/null
# Binaries that link it dynamically
for b in /usr/local/bin/* /opt/*/bin/*; do
ldd "$b" 2>/dev/null | grep -q libbrpc && echo "$b"
done
# Statically linked binaries still carry bRPC symbol names
nm -C --defined-only ./your-service 2>/dev/null | grep -c 'brpc::Server::Start'
A static link leaves symbols but no reliable version string, so for those you need the build record or the source tree that produced the binary.
3. Check what each server exposes
From a host on the same network as a would-be attacker, not from inside the service's own subnet, test whether builtin services answer on the public port:
curl -s -o /dev/null -w '%{http_code}\n' -m 3 http://SERVICE_HOST:PUBLIC_PORT/status
curl -s -o /dev/null -w '%{http_code}\n' -m 3 http://SERVICE_HOST:PUBLIC_PORT/vars
A 200 means builtin services are on the public listener. The bRPC documentation also gives a one line check for whether /dir and /threads are enabled, which should never be true on a public port. In code, look for ServerOptions settings: auth, internal_port, has_builtin_services, enabled_protocols, redis_service, rtmp_service, and the gflags -immutable_flags, -enable_dir_service and -enable_threads_service.
4. Reduce exposure until you can upgrade
These controls come from the project's own documentation and threat model:
- Set
has_builtin_services = falsewhere they are not needed, or setinternal_portand firewall it. Before 1.18.0internal_portalone was bypassable, so the firewall is the real control. - Restrict
enabled_protocolsto what you serve; if you never speak RTMP, Redis or nshead, do not accept them. - Front HTTP services with a proxy that forwards only named paths and rejects doubled slashes and ambiguous framing headers.
- Set
-immutable_flags=trueand run bRPC as an unprivileged user. - Keep bRPC Redis, Thrift, MySQL and Discovery clients pointed at servers you control, with mutual TLS across untrusted networks.
5. Upgrade to 1.18.0, or backport the patches
Bump the version in whatever pulls bRPC in:
# CMake FetchContent example
FetchContent_Declare(brpc
URL https://github.com/apache/brpc/archive/refs/tags/1.18.0.tar.gz)
# A vars.sh style third party script
BRPC_DOWNLOAD="https://github.com/apache/brpc/archive/refs/tags/1.18.0.tar.gz"
If you are on a fork or an old line you cannot leave this quarter, every CVE has a single named pull request. Start with 3308, 3525, 3511 and 3512 for the access control issues, then 3474, 3476, 3343, 3462, 3325 and 3354 for the parsers that face the network on the most common configurations, then the rest by which features you enable. Run the project's unit tests after each cherry pick; several fixes touch the same HPACK and stream files.
6. Rebuild and redeploy everything that links it
A library fix does nothing until the binaries that link it are rebuilt. For static links that means every service, not just a shared package. Track rebuilds by service and image digest, not by ticket.
7. Test the new limits, then verify
Replay representative traffic and watch for HTTP 413, h2 REFUSED_STREAM, EMSGSIZE on streams, depth errors and HTTP 403 on internal_port. Raise a limit only for a named client that needs it. Then re-run steps 1 to 3: builtin paths on an authenticated public port should demand credentials, and every build file should reference 1.18.0 or a fork with the named patches.
What changed since first reports
Early summaries listed 33 of the 35 titles. The full Apache text adds CVE-2026-80463 (unbounded stream reassembly memory) and CVE-2026-82425 (a reachable assertion on a revived client socket), both moderate and fixed in 1.18.0. Since 21 October the only changes are CISA's enrichment on three records and NVD's deferral; no exploitation reports had appeared by 24 October.
Open questions
- Downstream exposure. No vendor shipping bRPC inside a product had published an assessment we could find by 24 October.
- Patched forks. How many customised forks already carried equivalent fixes is unknown.
- Scores. Most of these CVEs may never get an NVD score. Prioritise by reachability in your configuration.
- Why 1.17.0 is listed as affected. PR 3308 was merged on 25 May and 1.17.0 shipped on 28 May, yet the advisory lists 1.17.0 as affected. The release was probably cut before the merge, but we have not confirmed the branch history. Follow the advisory.
What would have helped
There was no reported attack. The useful question is how to make a batch like this an easy job, and how to have taken the fix in September instead of late October.
Practices any team can use
- Keep a manifest for native dependencies. Record the name, version and source URL of every C++ library fetched by a script or vendored, and generate an SBOM from it at build time.
- Watch releases, not only CVE feeds. The 1.18.0 notes were full of hardening language five weeks before the CVEs. Follow the GitHub release feed or
announce@apache.organd take minor releases on a schedule. - Read the threat model of anything you embed. bRPC's says authentication is per connection, builtin services are on by default and client TLS verification is off by default.
- Separate administration from service traffic at the network layer. An internal port is only internal if a firewall makes it so.
- Turn off what you do not use.
enabled_protocols,has_builtin_servicesandimmutable_flagsshrink the attack surface for free. - Plan for forks. If you run a customised fork, keep a list of upstream security PRs you have and have not ported, and assign an owner.
Where Safeguard fits
Start with where bRPC actually lives. A lockfile or package manifest is where most dependency scanning looks first, and a bRPC tarball fetched by a CMake or shell script, or copied into a vendored directory, is not declared there. So feed the scan an input that does name it: the built binary or container image, or an SBOM your build produces.
- Bring your own SBOM. If your build generates an SBOM that lists bRPC with its version, uploading that SBOM to Safeguard matches it against vulnerability databases, and the platform then shows which projects contain that component and version.
- Track the services around it.
safeguard scan --dir .andsafeguard scan --image <name>cover the rest of what those services ship, written as JSON under./output, so the rebuild for bRPC can also pick up other fixes. - Keep old versions out. Policies and gates evaluated in the platform can block promotion of a build whose SBOM still lists bRPC below 1.18.0.
- Do the edit. The Safeguard CLI's assistant can change a
vars.sh, a CMakeFetchContentURL or a Bazel module version to 1.18.0, run your build and tests, and ask before each command under the default permission mode.safeguard execruns the same work in CI. Autonomous remediation can open fix pull requests and ships switched off.
Where it does not help: Safeguard does not change ServerOptions in a running service, write your firewall rules, or tell you which bRPC features a closed source product enables. When bRPC is embedded in a vendor's product, the fix has to come from that vendor.
To try the CLI on your own repositories and images, download Safeguard and read the CLI docs.
The same release first, CVEs later pattern showed up the same day in Apache IoTDB 2.0.11; the link between the two is timing only. For the response process when a shared dependency turns out to be vulnerable, see our incident response playbook for a compromised dependency.
Common mistakes and troubleshooting
- "We set internal_port, so builtin services are safe." Not before 1.18.0; see CVE-2026-84748 and CVE-2026-86249. Firewall the port and upgrade.
- "We have authentication, so pre-auth parser bugs do not apply." The h2, Redis, RTMP and mcpack parsers run before the Authenticator.
- "We scanned the repo and found nothing." Package based scanners cannot see a library pulled in by a script or vendored directory.
- Upgrading the library but not the binaries. Static links keep the old code until rebuilt and redeployed.
- Breaking monitoring. Dashboards that scraped
/varson the public port of an authenticated server will fail after the upgrade; move them to the internal port. - Cherry picks that conflict. Several patches touch the HPACK, HTTP/2 and stream code; apply them in PR number order and run tests between each.
FAQ
What is CVE-2026-48830 in Apache bRPC?
A high rated authentication bypass. With ServerOptions.auth enabled and builtin HTTP services on the public listener, a keep-alive connection could be treated as authenticated without credentials, so later requests to protected endpoints skipped the check. It affects bRPC through 1.17.0 and is fixed in 1.18.0 and PR 3308.
Which versions are affected and which version fixes them?
All 35 CVEs affect bRPC through 1.17.0; CVE-2026-79704 specifically affects 1.11.0 through 1.17.0. All are fixed in 1.18.0, released on GitHub on 17 September 2026. Each CVE also names a single pull request for teams that need to backport.
Is anyone exploiting these vulnerabilities?
No exploitation is reported. None are in the CISA KEV catalog as of version 2026.10.23, CISA's enrichment on three records says "Exploitation: none", and we found no public proof of concept.
What is the CVSS score?
Apache did not publish CVSS scores, only high and moderate ratings. CISA's enrichment scored CVE-2026-56386 and CVE-2026-82230 at 7.5 and CVE-2026-84727 at 5.4. NVD deferred CVE-2026-48830 without a score.
We set internal_port. Are we protected?
Partly, and not on 1.17.0 or earlier. CVE-2026-86249 and CVE-2026-84748 are both bypasses involving internal_port. Keep the internal port behind a firewall, restrict enabled protocols, and upgrade.
Do we need to upgrade services that only use bRPC as a client?
Yes. Redis, Thrift, MySQL, Discovery, multi stream RPC, TLS name checks and health checks all have client side CVEs in this batch.
Will 1.18.0 break anything?
Possibly. It enforces new parsing limits, rejects some old HTTP header forms, stops serving ordinary services on internal_port, requires credentials for builtin services on authenticated public ports, and moves to a C++14 baseline. See the limits table above and test before rollout.
Is Apache Doris or StarRocks affected?
Their master branch build scripts referenced older bRPC tarballs (1.4.0 and 1.9.0) on 24 October. Neither had published an assessment we could find, and they may patch or disable the affected features. Check with each project before drawing a conclusion.
bRPC is a good case for this section because every CVE comes with a small, named patch. If your service is pinned to a fork or an old line, backporting those pull requests into your own build is realistic today, and it is the same pattern the steps below describe.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.
3. Gold Registry: start from components that are already fixed
Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | Safeguard policies and gates in CI |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would have helped
None of these demos shows bRPC; each shows a real flow that maps onto this upgrade.
The first is a real Safeguard CLI session. It installs the CLI, opens the interactive terminal and asks it to fix a lodash CVE: the assistant reads the finding and advisory, asks before any command that changes something, edits package.json to lodash 4.17.21, runs npm install and npm test with approval, and pushes nothing. For bRPC you would ask it to change the tarball URL in your third party script or the FetchContent line in CMake to 1.18.0, then approve the build and the test run one command at a time.
Click through it at your own pace, or open it full screen.
The second demo sets up the Safeguard runner on your own machine, approves it with a device code and then scans from the terminal. That is how you would scan the SBOMs and images your C++ builds produce and ask which still list bRPC below 1.18.0.
Click through it at your own pace, or open it full screen.
The third demo is a real desktop app session. The CLI session appears in the conversation list, you ask for work on your computer, pick the folder, and Approve or Deny each command and file edit; it ends with an upgrade done and tests passing. Here you would pick the repository of a service that links bRPC, let it propose the version bump plus has_builtin_services = false where the service does not need them, and approve each edit and build.
Click through it at your own pace, or open it full screen.
Quick check
Your bRPC 1.16 server uses an Authenticator and sets internal_port. Is it safe from the auth bypasses?
No. CVE-2026-86249 and CVE-2026-84748 are bypasses that involve internal_port, and the parser bugs run before authentication anyway. Firewall the internal port, restrict enabled protocols and upgrade to 1.18.0.
Your dependency scanner reports no bRPC in a C++ repository. Are you done?
Not yet. bRPC usually arrives through a build script, a CMake or Bazel rule or a vendored directory, which package based scanners cannot see. Search the build files and binaries, then generate an SBOM that lists it.
Sources
- oss-security: Apache bRPC security advisory, 35 vulnerabilities fixed in 1.18.0 (openwall.com)
- Apache announce list: Apache bRPC security advisory (lists.apache.org)
- Apache bRPC 1.18.0 release notes (github.com)
- Apache bRPC 1.17.0 release (github.com)
- CVE-2026-48830 record (cve.org)
- CVE-2026-56386 record with CISA enrichment (cve.org)
- CVE-2026-82230 record with CISA enrichment (cve.org)
- CVE-2026-84727 record with CISA enrichment (cve.org)
- CVE-2026-90484 record (cve.org)
- NVD: CVE-2026-48830 (nvd.nist.gov)
- CISA Known Exploited Vulnerabilities catalog (cisa.gov)
- PR 3308: apply auth check to builtin requests on public port (github.com)
- PR 3343: HPACK dynamic table size update recursive decoding (github.com)
- PR 3344: limit nested container depth in Redis reply and AMF parsers (github.com)
- Apache bRPC THREAT_MODEL.md (github.com)
- Apache bRPC SECURITY.md (github.com)
- Apache bRPC server documentation, security section (github.com)
- Apache bRPC builtin services documentation (github.com)
- Apache bRPC CMakeLists.txt at 1.18.0 (github.com)
- Apache bRPC community case list (github.com)
- Apache Doris third party build script, vars.sh (github.com)
- StarRocks third party build script, vars.sh (github.com)
- vcpkg brpc port (github.com)
Last reviewed: 24 October 2026. This is a developing story; check the linked advisories for the latest status.