This post is also available in:
On June 25, 2026, Percona released 8.0.26-11 of Percona Server for MongoDB with an urgent upgrade recommendation. This release patches 10 high-severity CVEs affecting all 8.0.x versions.
This post walks through the upgrade performed in a real lab environment: a 3-node Replica Set on Oracle Linux 8, with zero application downtime.
Why upgrade now?
CVE-2026-9740 alone is enough reason. It allows an unauthenticated user to crash mongod via a crafted BSON input. Any exposed port is a DoS vector with no authentication required.
CVEs fixed in this release
| CVE | Severity | Impact |
|---|---|---|
| CVE-2026-11933 | High | Use-after-free in JS engine ($where, $function) — information disclosure or crash |
| CVE-2026-9740 | High | BSON validator — DoS by unauthenticated user |
| CVE-2026-9743 | High | Aggregation framework — DoS via malicious cursor |
| CVE-2026-9753 | High | $_internalApplyOplogUpdate — server crash |
| CVE-2026-9752 | High | 2dsphere index — crash via crafted document |
| CVE-2026-9750 | High | Query execution — crash and incorrect results |
| CVE-2026-9749 | High | $exchange stage — crash on key-range partitioning |
| CVE-2026-9748 | High | $_internalConvertBucketIndexStats + $facet — crash |
| CVE-2026-9747 | High | fromRouter: true + runtimeConstants.userRoles — crash |
| CVE-2026-9746 | High | $changeStream + $_requestReshardingResumeToken — crash |
| CVE-2026-9751 | Medium | setParameter was logging credentials in plaintext (e.g. ldapQueryPassword) |
The mongodump/tools binaries were also rebuilt with golang.org/x/crypto v0.52.0 and golang.org/x/net v0.55.0, closing 15 additional Go library CVEs.
Lab environment
| Host | IP | Role |
|---|---|---|
| mongo-vm01 | 192.168.15.180 | PRIMARY |
| mongo-vm02 | 192.168.15.181 | SECONDARY |
| mongo-vm03 | 192.168.15.182 | SECONDARY |
- OS: Oracle Linux 8
- Replica Set:
rs-source - From:
8.0.23-10/ To:8.0.26-11
Is there downtime?
No, as long as the application connection string uses retryWrites=true:
mongodb://host1,host2,host3/?replicaSet=rs-source&retryWrites=trueRolling upgrade keeps the cluster online throughout. The only impact is ~5-15 seconds without writes during the primary election. Modern drivers handle this transparently with automatic retry.
Pre-checks (required)
1. Validate cluster health
mongosh --quiet --eval '
rs.status().members.forEach(m => print(m.name + " | " + m.stateStr + " | health=" + m.health));
print("---");
print("Version: " + db.version());
print("fCV: " + JSON.stringify(db.adminCommand({getParameter:1, featureCompatibilityVersion:1}).featureCompatibilityVersion));
'Output from lab:
192.168.15.180:27017 | PRIMARY | health=1
192.168.15.181:27017 | SECONDARY | health=1
192.168.15.182:27017 | SECONDARY | health=1
---
Version: 8.0.23-10
fCV: {"version":"8.0"}✅ All 3 nodes healthy, fCV
8.0— ready to proceed.
2. Check package availability
Run on each node:
sudo dnf clean all && sudo dnf makecache
sudo dnf --showduplicates list percona-server-mongodb 2>/dev/null | grep 8.0.26Expected output:
percona-server-mongodb.x86_64 8.0.26-11.el8 psmdb-80-release-x86_643. Check currently installed packages
rpm -qa | grep -i percona-server-mongodb | sortOutput from lab:
percona-server-mongodb-8.0.23-10.el8.x86_64
percona-server-mongodb-mongos-8.0.23-10.el8.x86_64
percona-server-mongodb-server-8.0.23-10.el8.x86_64
percona-server-mongodb-tools-8.0.23-10.el8.x86_64Getting the packages
Option A — Download via Percona repository (internet access available)
sudo dnf install -y dnf-plugins-core
mkdir -p /tmp/psmdb-8.0.26-11
sudo dnf download \
--releasever=8 \
--arch=x86_64 \
--destdir=/tmp/psmdb-8.0.26-11 \
percona-server-mongodb-8.0.26-11.el8 \
percona-server-mongodb-server-8.0.26-11.el8 \
percona-server-mongodb-mongos-8.0.26-11.el8 \
percona-server-mongodb-tools-8.0.26-11.el8Option B — Download on Windows, transfer to Linux
For air-gapped or restricted environments.
Download via PowerShell:
$base = "https://downloads.percona.com/downloads/percona-server-mongodb-8.0/percona-server-mongodb-8.0.26-11/binary/redhat/8/x86_64"
$dest = "C:\tmp\psmdb-8.0.26-11"
New-Item -ItemType Directory -Force -Path $dest
@(
"percona-server-mongodb-8.0.26-11.el8.x86_64.rpm",
"percona-server-mongodb-server-8.0.26-11.el8.x86_64.rpm",
"percona-server-mongodb-mongos-8.0.26-11.el8.x86_64.rpm",
"percona-server-mongodb-tools-8.0.26-11.el8.x86_64.rpm"
) | ForEach-Object {
Invoke-WebRequest -Uri "$base/$_" -OutFile "$dest\$_"
Write-Host "Downloaded: $_"
}Transfer via SCP:
$dest = "C:\tmp\psmdb-8.0.26-11"
$hosts = @("192.168.15.180", "192.168.15.181", "192.168.15.182")
foreach ($h in $hosts) {
ssh root@$h "mkdir -p /tmp/psmdb-8.0.26-11"
scp "$dest\*.rpm" "root@${h}:/tmp/psmdb-8.0.26-11/"
Write-Host "Transferred to $h"
}Validate packages (required for both options)
for f in /tmp/psmdb-8.0.26-11/*.rpm; do
echo "=== $(basename $f) ==="
rpm -K "$f"
doneOutput from lab:
=== percona-server-mongodb-8.0.26-11.el8.x86_64.rpm ===
/tmp/psmdb-8.0.26-11/percona-server-mongodb-8.0.26-11.el8.x86_64.rpm: digests signatures OK
...If you see
NOKEY, import the Percona GPG key: “bash sudo rpm --import /etc/pki/rpm-gpg/PERCONA-PACKAGING-KEY“
Dry-run (simulate without installing)
sudo dnf install --assumeno /tmp/psmdb-8.0.26-11/*.rpmExpected output:
Upgrading:
percona-server-mongodb x86_64 8.0.26-11.el8 @commandline 8.2 k
percona-server-mongodb-mongos x86_64 8.0.26-11.el8 @commandline 32 M
percona-server-mongodb-server x86_64 8.0.26-11.el8 @commandline 70 M
percona-server-mongodb-tools x86_64 8.0.26-11.el8 @commandline 33 M
Upgrade 4 Packages
Operation aborted.✅ Only
Upgrading— no newInstalling, noRemoving. “Operation aborted” is the expected behavior of--assumeno.
Rolling Upgrade — one node at a time
Execution order:
1. mongo-vm03 (192.168.15.182) -- SECONDARY
2. mongo-vm02 (192.168.15.181) -- SECONDARY
3. mongo-vm01 (192.168.15.180) -- PRIMARY (stepDown first)Node 1 — mongo-vm03 (SECONDARY)
mongosh --quiet --eval "rs.status().members.find(m => m.self).stateStr"
sudo systemctl stop mongod
sudo dnf install -y /tmp/psmdb-8.0.26-11/*.rpm
/usr/bin/mongod --version && \
sudo systemctl start mongod && \
sleep 5 && \
mongosh --quiet --eval "rs.status().members.find(m => m.self).stateStr"Output from lab:
db version v8.0.26-11
...
SECONDARYCheck replication lag:
mongosh --quiet --eval "rs.printSecondaryReplicationInfo()"source: 192.168.15.182:27017
replLag: '-10 secs (0 hrs) behind the primary'✅ Zero lag (negative value is normal — node slightly ahead of the primary snapshot).
Node 2 — mongo-vm02 (SECONDARY)
Same sequence as Node 1:
mongosh --quiet --eval "rs.status().members.find(m => m.self).stateStr"
sudo systemctl stop mongod
sudo dnf install -y /tmp/psmdb-8.0.26-11/*.rpm
/usr/bin/mongod --version && sudo systemctl start mongod && sleep 5 && \
mongosh --quiet --eval "rs.status().members.find(m => m.self).stateStr"Output from lab:
db version v8.0.26-11
...
SECONDARYmongosh --quiet --eval "rs.printSecondaryReplicationInfo()"source: 192.168.15.181:27017
replLag: '0 secs (0 hrs) behind the primary'
source: 192.168.15.182:27017
replLag: '0 secs (0 hrs) behind the primary'✅ Both secondaries on
8.0.26-11with zero lag.
Node 3 — mongo-vm01 (PRIMARY)
⚠️ Do not stop the primary directly. Run
replSetStepDownfirst to trigger a clean election.
StepDown:
mongosh --quiet --eval "db.adminCommand({ replSetStepDown: 60, secondaryCatchUpPeriodSecs: 30 })"Output:
{ ok: 1 }Confirm new topology:
mongosh --quiet --eval "rs.status().members.forEach(m => print(m.name + ' | ' + m.stateStr))"192.168.15.180:27017 | SECONDARY
192.168.15.181:27017 | PRIMARY
192.168.15.182:27017 | SECONDARY✅
mongo-vm01is now SECONDARY.mongo-vm02elected as new PRIMARY.
Stop, install, start:
sudo systemctl stop mongod
sudo dnf install -y /tmp/psmdb-8.0.26-11/*.rpm
/usr/bin/mongod --version && sudo systemctl start mongod && sleep 5 && \
mongosh --quiet --eval "rs.status().members.find(m => m.self).stateStr"Output from lab:
db version v8.0.26-11
...
SECONDARYFinal validation
mongosh --quiet --eval '
rs.status().members.forEach(m => print(m.name + " | " + m.stateStr));
print("---");
db.adminCommand({getParameter:1, featureCompatibilityVersion:1}).featureCompatibilityVersion;
rs.printSecondaryReplicationInfo();
'Output from lab:
192.168.15.180:27017 | PRIMARY
192.168.15.181:27017 | SECONDARY
192.168.15.182:27017 | SECONDARY
---
{ version: '8.0' }
source: 192.168.15.181:27017
replLag: '0 secs (0 hrs) behind the primary'
source: 192.168.15.182:27017
replLag: '0 secs (0 hrs) behind the primary'✅ Cluster fully healthy on
8.0.26-11.
Note:
mongo-vm01returned as PRIMARY via election after startup — expected behavior, as it has a higher priority configured in the replica set.
Summary
| Node | IP | Previous | Current |
|---|---|---|---|
| mongo-vm03 | 192.168.15.182 | 8.0.23-10 | 8.0.26-11 |
| mongo-vm02 | 192.168.15.181 | 8.0.23-10 | 8.0.26-11 |
| mongo-vm01 | 192.168.15.180 | 8.0.23-10 | 8.0.26-11 |
- Effective downtime: ~5-10s during primary election
- fCV: kept at
8.0— no action required - CVEs closed: 10 high + 1 medium on the server; 15 Go CVEs in tools
