From 7ca1ff0a7e8f0e7df485679c58c755158b1f9829 Mon Sep 17 00:00:00 2001 From: jack Date: Sat, 18 Oct 2025 14:24:56 +0200 Subject: [PATCH] Fix P1: Add DoS protections to PeerID fragment handler Critical security fix addressing Codex review feedback: The PeerID overload of handleFragment (which is actually called by CoreBluetooth) was missing key safety checks that existed in the String overload: 1. Added total <= 10000 check to prevent unbounded fragment counts 2. Added cumulative size check against FileTransferLimits before storing each fragment 3. Prevents memory exhaustion DoS attacks via malicious fragment streams This ensures the actually-used code path has proper bounds checking. --- bitchat/Services/BLEService.swift | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/bitchat/Services/BLEService.swift b/bitchat/Services/BLEService.swift index 64e1f1a9..a2c291e3 100644 --- a/bitchat/Services/BLEService.swift +++ b/bitchat/Services/BLEService.swift @@ -3414,8 +3414,8 @@ extension BLEService { let originalType = packet.payload[12] let fragmentData = packet.payload.suffix(from: 13) - // Sanity checks - guard total > 0 && index >= 0 && index < total else { return } + // Sanity checks - add reasonable upper bound on total to prevent DoS + guard total > 0 && total <= 10000 && index >= 0 && index < total else { return } // Store fragment let key = FragmentKey(sender: senderU64, id: fragU64) @@ -3431,6 +3431,27 @@ extension BLEService { incomingFragments[key] = [:] fragmentMetadata[key] = (originalType, total, Date()) } + + // Check cumulative size before storing this fragment + let currentSize = incomingFragments[key]?.values.reduce(0) { $0 + $1.count } ?? 0 + let assemblyLimit: Int = { + if originalType == MessageType.fileTransfer.rawValue { + // Allow headroom for TLV metadata and binary framing overhead. + return FileTransferLimits.maxFramedFileBytes + } + return FileTransferLimits.maxPayloadBytes + }() + guard currentSize + fragmentData.count <= assemblyLimit else { + // Exceeds size limit - evict this assembly + SecureLogger.warning( + "🚫 Fragment assembly exceeds size limit (\(currentSize + fragmentData.count) bytes > \(assemblyLimit)), evicting", + category: .security + ) + incomingFragments.removeValue(forKey: key) + fragmentMetadata.removeValue(forKey: key) + return + } + incomingFragments[key]?[index] = Data(fragmentData) // Check if complete