Skip to content

fix(deps): update module github.com/rabbitmq/amqp091-go to v1.14.0 [security] - #134

Open
renovate[bot] wants to merge 1 commit into
developfrom
renovate/go-github.com-rabbitmq-amqp091-go-vulnerability
Open

renovate[bot] wants to merge 1 commit into
developfrom
renovate/go-github.com-rabbitmq-amqp091-go-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
github.com/rabbitmq/amqp091-go v1.9.0 → v1.14.0 age confidence

amqp091-go has a Potential Memory Exhaustion/Protocol Violation via Broker-Controlled Oversized Payload

CVE-2026-79921 / GHSA-6c5v-hqjr-5xxp

More information

Details

Summary
A vulnerability exists in the amqp091-go client library where a compromised or malicious AMQP broker can force the client to allocate resources for and process content body frames that exceed the negotiated frame_max limit. This can lead to unexpected memory consumption or application-layer denial of service (DoS), bypassing the protocol's built-in framing constraints.

Details
During a standard AMQP 0-9-1 connection handshake, the client and the broker negotiate a maximum frame size (frame_max), for example, 4096 bytes.

However, after negotiation, a malicious broker can send a valid basic.deliver sequence containing a content body frame whose header declares a payload size larger than the negotiated frame_max. Instead of enforcing the agreed-upon limit and closing the connection with a frame-error (as mandated by the AMQP 0-9-1 specification), the amqp091-go client:

  1. Accepts the broker-declared oversized frame size.
  2. Allocates memory based on this oversized declaration.
  3. Reads the payload, assembles it into the message, and delivers it to the consumer.

Impact

  • Denial of Service (DoS): If a broker sends extremely large frame sizes, it can trigger significant memory allocations on the client side, potentially leading to Out-Of-Memory (OOM) crashes.
  • Protocol Violation: The client fails to enforce negotiated connection parameters, trusting the broker implicitly even after constraints have been established.

Severity

  • CVSS Score: 8.9 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


RabbitMQ amqp091-go: Resource Exhaustion (OOM) via Unbounded Body Buffer Allocation

CVE-2026-77410 / GHSA-r9c8-gcjp-xfwh

More information

Details

Summary
A flaw in the recvContent function allows a malicious AMQP server to trigger an Out-of-Memory (OOM) error, forcing the host operating system or container runtime to immediately terminate the client process.

Vulnerability Details
When receiving message content payloads, the client processes the expected size from the content header framework. The recvContent function attempts to optimize performance by pre-allocating memory for the message body based on the ch.header.Size field, which is a 64-bit unsigned integer (uint64).

// channel.go:495-496
if cap(ch.body) == 0 {
    ch.body = make([]byte, 0, ch.header.Size)  // unbounded
}

The underlying library fails to validate or cap this requested size against any upper boundary—such as the maximum frame size negotiated during connection establishment (FrameMax). If a server specifies an extreme body size (e.g., 2^62 bytes), the Go runtime attempts to allocate an exabyte-scale slice capacity. This immediately exhausts available system memory, causing the operating system's OOM killer to terminate the application.

Attack Vector / Exploitation Scenario

  • Message Delivery Phase: A malicious or compromised AMQP broker sends a standard basic.deliver frame containing a content header with an intentionally inflated body-size variable.
  • Authentication Requirement: No special privileges or authentication bypasses are required; the crash occurs seamlessly during normal message consumption.

Impact

  • Availability: High. Exploded memory consumption results in an instant process termination, destroying application state and availability for all threads sharing the environment.

Severity

  • CVSS Score: 8.9 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


RabbitMQ amqp091-go: Consumer Message Flooding via Signed-to-Unsigned Integer Casting in Qos Configuration

CVE-2026-77406 / GHSA-rm6m-hrcw-jw33

More information

Details

Summary

A logic and resource exhaustion vulnerability exists in the AMQP client's Quality of Service (Qos) configuration method. The Qos function accepts signed integers (int) for the prefetchCount and prefetchSize parameters but casts them directly to unsigned integers (uint16 and uint32, respectively) when formatting the wire-level frame.

If a developer passes a negative integer (such as -1) to these parameters—frequently intended as a sentinel value meaning "no change" or "no limit"—the application performs an implicit signed-to-unsigned conversion. This wraps the values to their absolute maximum limit ($65535$ and $4294967295$). Consequently, a consumer expecting restricted message delivery rates is suddenly flooded with an unlimited volume of messages, potentially exhausting memory resources and crashing the application.


Vulnerability Details
Mechanism

The bug manifests during the structural assignment inside the channel's Qos method:

// channel.go:795-796
PrefetchCount: uint16(prefetchCount),  // -1 wraps to 65535
PrefetchSize:  uint32(prefetchSize),   // -1 wraps to 4294967295

In Go, converting a negative signed integer to an unsigned integer shifts the value via two's complement arithmetic. Because no boundary validation or signedness check occurs prior to the cast:

  • Passing -1 for prefetchCount yields a wire value of 65535.
  • Passing -1 for prefetchSize yields a wire value of 4294967295.
Impact

The AMQP broker interprets a prefetch-count of 65535 as an instruction to dispatch messages to the consumer with virtually no concurrency limits.

If the application is processing heavy payloads or relies on strict rate-limiting to maintain stability, this unexpected flood will cause rapid heap memory growth, unmanageable processing queues, and an eventual Out-Of-Memory (OOM) termination.


Attack Vector

An attacker who can manipulate configuration files, environmental variables, or API inputs that dictate client Qos settings can trigger an application-layer Denial of Service:

  1. Malicious Input: An attacker sets a service's prefetch configuration parameter to -1.
  2. Implicit Overflow: The application initializes the channel, executes Qos(-1, ...), and transmits an unintended maximum-capacity request to the RabbitMQ/AMQP broker.
  3. Consumer Exhaustion: The broker flushes the entire contents of the queue directly into the client consumer's network buffer, bypassing expected application concurrency barriers and inducing a crash.

Severity

  • CVSS Score: 8.2 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:L

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


RabbitMQ amqp091-go: Denial of Service via Malicious Field Length in AMQP Client

CVE-2026-77412 / GHSA-4v58-74mf-rjx3

More information

Details

Summary
A vulnerability in the readField function allows a malicious or compromised AMQP server to trigger an unhandled runtime panic in the client application, leading to an immediate crash of the entire process.

Details
When parsing incoming AMQP frames, the readField function processes byte-array fields (type tag 'x') by reading a 32-bit big-endian integer to determine the length of the data payload.

// read.go:253-263
case 'x':
    var len int32
    if err = binary.Read(r, binary.BigEndian, &len); err != nil {
        return nil, err
    }
    value := make([]byte, len)  // PANICS if len < 0

If a server transmits a length value of 0xFFFFFFFF, it is interpreted by the client as a signed 32-bit integer with a value of -1. Passing a negative integer to Go's built-in make() function for slice allocation triggers an unrecoverable runtime panic (panic: len out of range).

Because the reader goroutine handles network I/O without an explicit recover() wrapper, this panic propagates up to the runtime root, abruptly terminating the host application.

Attack Vector / Exploitation Scenario
An attacker capable of spoofing, compromising, or controlling an AMQP broker can exploit this flaw during two primary phases:

  1. Connection Establishment: Sending a malicious connection.start handshake frame containing server-properties with an 'x' type field assigned a negative length.
  2. Message Delivery: Delivering a message payload where the header table contains a malformed field matching the criteria above.

Impact
Availability: High. A single malformed frame can reliably crash the client process, resulting in a persistent Denial of Service (DoS) if the client automatically reconnects and receives the same payload.

Severity

  • CVSS Score: 8.9 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


RabbitMQ amqp091-go: Denial of Service via Sub-Spec Frame Size Negotiation

CVE-2026-77403 / GHSA-xwwf-m8fg-p9q2

More information

Details

Summary

A Denial of Service (DoS) vulnerability exists in the AMQP client's connection negotiation logic. The AMQP specification explicitly mandates a strict minimum frame size of 4096 bytes to prevent pathological packet fragmentation. While the library defines a frameMinSize = 4096 constant, the connection negotiation loop fails to enforce this boundary, blindly accepting whatever maximum frame size (FrameMax) the server advertises during the handshake.

If a client connects to a malicious or compromised AMQP broker that advertises an extremely low FrameMax (such as 1 byte), the negotiation succeeds. Consequently, every subsequent message transmission is forced to splinter into thousands or millions of single-byte frames, causing massive CPU overhead, thread contention, and a near-instantaneous application freeze.


Vulnerability Details
Mechanism

During the connection establishment phase, the client and server negotiate connection parameters—including maximum channel count, heartbeat intervals, and maximum frame sizes. The vulnerability is located where the client accepts the server's tuning parameters:

// Connection negotiation logic maps server values directly without validation
if serverSettings.FrameMax > 0 {
    // VULNERABILITY: Lacks a floor validation check against frameMinSize (4096)
    c.config.FrameMax = serverSettings.FrameMax 
}

Because there is no conditional check asserting that serverSettings.FrameMax >= frameMinSize, a value below the protocol specification floor is successfully registered. When the application later passes data payloads to the frame writer, the chunking algorithm splits the payload using the negotiated FrameMax value as its chunk window divisor.

Impact

When FrameMax is set to an absurdly low threshold (e.g., 1 to 10 bytes):

  • A standard 10 KiB message payload requires tens of thousands of individual write operations and frame headers.
  • The system's CPU becomes entirely bound by frame serialization, memory allocation for frame structures, and context switching within the network output loops.
  • This results in an application-layer Denial of Service (DoS) affecting not just the specific AMQP connection, but potentially the entire host system due to CPU resource starvation.

Attack Vector

An attacker who compromises an upstream AMQP broker, performs a Man-in-the-Middle (MitM) interception, or tricks an application into connecting to an unauthorized external rogue broker can trigger this vulnerability:

  1. Rogue Handshake: The client application connects to an AMQP endpoint controlled by the attacker.
  2. Malicious Parameter Tuning: During the connection.tune phase, the rogue server returns a FrameMax value of 1.
  3. Resource Exhaustion Trigger: The client completes the handshake successfully. As soon as the client attempts to publish a message or process traffic, the internal loop fragments the data into single-byte frames, spiking the host's CPU usage to 100% and disabling the application thread.

Severity

  • CVSS Score: 8.9 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


RabbitMQ amqp091-go: Connection Configuration Overwrite via Unsanitized TLS Path Parameter Injection

CVE-2026-77404 / GHSA-465g-fh3v-9jw4

More information

Details

Summary

A query parameter injection vulnerability exists in the AMQP client's connection URI formatting logic. When generating or parsing connection URIs, TLS-related filesystem paths (such as certificates or keys) are appended directly to the URI's query string using string concatenation rather than secure URL encoding via functions like url.QueryEscape.

If an application handles a TLS file path containing special character delimiters (such as & or =), these characters are interpreted as parameter separators by the URI parser. If the resulting URI.String() output is subsequently re-parsed via ParseURI, the injected fields can silently overwrite or hijack critical configuration parameters, forcing the client to use arbitrary connection settings or alternate TLS files.


Vulnerability Details
Mechanism

The vulnerability lies within the lack of proper escaping when compiling connection string components into a raw URL format:

// Example of insecure string concatenation during URI building
uri := fmt.Sprintf("amqps://user:pass@host/%s?certfile=%s&keyfile=%s", vhost, certPath, keyPath)

Because certPath and keyPath are not passed through url.QueryEscape, special URL characters preserve their control meanings. For instance, if a user supply a certificate path named:
/tmp/cert=foo&keyfile=/evil/path

The generated string translates into:
...?certfile=/tmp/cert=foo&keyfile=/evil/path&keyfile=/original/path

When this string passes back through ParseURI (common in connection re-dial routines or configuration replication steps), standard URL parsing mechanics treat the string as multiple distinct parameters. Depending on map assignment order inside the parser, the injected keys take precedence over the original parameters.

Impact

By manipulating the file paths used for TLS assets, an attacker or compromised local sub-system can:

  • Inject arbitrary alternative options or override protocol settings.
  • Substitute or switch keyfiles, leading to connection failures or the parsing of unauthorized cryptographic assets.
  • Corrupt connection state variables, triggering application-layer failures during connection setup or recovery.

Attack Vector

An attacker who has partial control over directory naming conventions or environmental variables used to specify local infrastructure paths can execute a parameter injection attack:

  1. Path Creation: An attacker sets up a path containing deliberate URL parameter delimiters (e.g., /var/lib/certs/client.crt?cacertfile=/tmp/fake_ca.crt&).
  2. String Generation: The application serializes the active connection state or passes the paths down to an unescaped URI builder function.
  3. Configuration Hijack: The URI string is generated with the injected parameter embedded into the query structure. When the client attempts to reuse or re-parse this connection string during a connection retry or worker spin-up, it parses the injected cacertfile parameter, loading a different, unverified Certificate Authority string.

Severity

  • CVSS Score: 8.7 / 10 (High)
  • Vector String: CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:L

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


RabbitMQ amqp091-go: Plaintext Credential Exposure via Exported PLAIN Authentication Struct Fields

CVE-2026-77407 / GHSA-27gv-rfvv-22mv

More information

Details

Summary

An information disclosure vulnerability exists in the AMQP client implementation's authentication handling configuration. Following a successful connection handshake, the Connection.Config.SASL field stores the Authentication implementation state used to establish the session.

For standard PLAIN authentication, this state utilizes the PlainAuth struct, which defines both Username and Password as publicly exported, plaintext string fields. Because this sensitive data is retained permanently in-memory within an exported field structure, any peripheral code, internal package, reflective logger, dependency, or automated debugging utility with access to the core *Connection object can read and expose the raw credentials.


Vulnerability Details
Mechanism

The vulnerability stems from the structural design of the configuration storage used during and after the AMQP handshake:

// auth.go:21-23
type PlainAuth struct {
    Username string
    Password string  // exported plaintext
}

When an application initializes a connection, the PlainAuth object is deeply nested inside the configuration structure (Connection.Config). Even after the handshake concludes and authentication is complete, this structure persists natively in-memory for the duration of the network connection's lifecycle.

Because Password is an exported string field, standard automated inspection mechanisms can read its value without restriction.

Affected Code Paths & Integrations

Any sub-component or library that traverses or reads the *Connection object will inadvertently read the plaintext password, including:

  • Reflective Loggers: Structured logging frameworks that serialize nested configuration structs into JSON/Log formats.
  • APM & Performance Agents: Automated telemetry or Application Performance Monitoring tools that capture state snapshots.
  • Debugging & Panic Handlers: Mid-tier software or dump libraries designed to capture goroutine state or print deep struct hierarchies upon program errors or signals.
Impact

The credential remains vulnerable to leak paths into logging pipelines, log aggregators, security information and event management (SIEM) systems, or standard output. Once transmitted to external log infrastructure, these credentials become accessible to unprivileged operators or any actor with access to log archives.


Attack Vector

An attacker does not necessarily need direct remote code execution to exploit this flaw; instead, the vulnerability acts as a credential harvesting vector inside multi-tenant environments or via secondary log exposure:

  1. Configuration Dump: An operator configures a standard reflective logger or third-party APM package to capture system state parameters, including the active AMQP *Connection object.
  2. Reflective Access: The inspection engine uses Go's reflect package to walk the structural hierarchy, pulling the string value from Connection.Config.SASL.(*PlainAuth).Password.
  3. Exfiltration: The plaintext password is written to standard system logs, which are then scraped into shared logging aggregators, exposing production infrastructure credentials to a wider audience.

Severity

  • CVSS Score: 7.0 / 10 (High)
  • Vector String: CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:L/SA:L

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


RabbitMQ amqp091-go: Missing Explicit TLS Minimum Version Configuration In URI Parser

CVE-2026-77405 / GHSA-33mj-cw25-m34h

More information

Details

Summary

A structural security weakness exists in the AMQP client's TLS configuration generator (tlsConfigFromURI). When constructing a *tls.Config object from an amqps:// connection URI, the library initializes the structure without explicitly defining the MinVersion field.

While modern versions of the Go compiler toolchain (Go 1.18+) default the implicit minimum version to TLS 1.2, this security posture relies entirely on an implicit toolchain dependency. If the library is compiled using legacy Go toolchains (Go < 1.18), or if a future toolchain introduces fallback behavior, the client could silently negotiate obsolete and insecure TLS 1.0 or TLS 1.1 protocols during connection handshakes with a compromised or malicious AMQP broker.


Vulnerability Details
Mechanism

The vulnerability lies in the lack of an explicit safety floor when assigning configurations inside the URI component:

// Example within uri.go's tlsConfigFromURI
cfg := &tls.Config{
    ServerName: host,
    // MinVersion is left completely unassigned (defaults to 0, or toolchain default)
}

In the Go standard library (crypto/tls), leaving MinVersion: 0 instructs the runtime to choose the toolchain's default minimum. Prior to Go 1.18, this default allowed negotiation down to TLS 1.0. Relying on implicit compiler configurations violates secure coding practices by decoupling the library's security posture from its source code, leaving applications vulnerable based solely on how they are built.

Impact

If a client application is built with a legacy compiler environment or a custom Go runtime, an attacker capable of executing a Man-in-the-Middle (MitM) attack can force the connection to downgrade to TLS 1.0 or 1.1. This exposes the AMQP protocol data stream to well-known cryptographic vulnerabilities (such as BEAST, POODLE, or SWEET32), allowing the attacker to decrypt or alter message payloads, connection parameters, and authentication credentials.


Attack Vector

An attacker performing a network-level downgrade attack can intercept a client connection built under a legacy toolchain:

  1. Interception: A client application compiled on a legacy pipeline attempts to establish an encrypted connection to an AMQP broker.
  2. Protocol Downgrade: The attacker intercepts the TLS Client Hello handshake and forces a downgrade negotiation to TLS 1.0.
  3. Cryptographic Exploitation: Because MinVersion was never explicitly locked to tls.VersionTLS12 by the library, the client accepts the weak cipher suites, allowing the attacker to monitor or manipulate the underlying AMQP session data.

Severity

  • CVSS Score: 9.4 / 10 (Critical)
  • Vector String: CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:N/SC:H/SI:L/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


RabbitMQ amqp091-go: Silent Data Truncation and State Corruption via Shortstr Integer Overflow

CVE-2026-77408 / GHSA-j497-x9hr-x34x

More information

Details

Summary

A data integrity and protocol corruption vulnerability exists in the AMQP client's property serialization logic. When encoding AMQP short string (shortstr) fields—such as identifiers, routing strings, and content metadata—the length of the string is explicitly cast to a fixed-size 8-bit unsigned integer (uint8).

If an application provides a property string exceeding 255 bytes, the length counter silently wraps around (e.g., a length of 300 wraps to 44). As a result, the parser writes only a truncated portion of the string into the outgoing connection buffer without returning an error. This leads to silent data corruption, broken RPC routing, and unpredictable broker-side state behavior.


Vulnerability Details
Mechanism

The vulnerability resides in the wire-level serialization logic for application publishing properties:

// write.go:246
length := uint8(len(b))  // wraps silently when len(b) > 255 (e.g., 300 -> 44)

Because Go allows silent integer truncation during explicit type casting, lengths larger than $2^8 - 1$ lose their most significant bits. The underlying stream writer reads length to determine how many bytes to pull from the buffer. Because no error or boundary check accompanies this truncation, the application believes the full payload was transmitted successfully.

Affected Properties

This truncation behavior affects every standard AMQP field serialized as a shortstr:

  • CorrelationId
  • ReplyTo
  • MessageId
  • Expiration
  • UserId
  • AppId
  • ContentType
  • ContentEncoding
  • Type
Impact

The critical consequence is silent protocol desynchronization at the application layer. The underlying TCP stream remains framed properly (because the shortened length matches the bytes written), but the business logic is corrupted. Distributed transactions, request-reply correlations, and tracing headers are truncated, causing downstream systems to drop messages or route them to incorrect consumers.


Attack Vector

An attacker who can influence metadata fields processed by an upstream application (such as a user-supplied tracking ID or a long content-type header) can exploit this to break system components:

  1. Targeting RPC Routing: A user passes a malicious or overly long CorrelationId of 300 bytes through an application endpoint.
  2. Silent Truncation: The library wraps the length value to 44, transmitting only the first 44 bytes to the rabbitMQ broker.
  3. Broken Correlation: When the service processes the request and responds, the replying consumer attempts to route the message using the full 300-byte identifier. Because the broker only recognizes the truncated 44-byte ID, the reply loop breaks silently, leading to hanging processes or data leaks across transaction boundaries.

Severity

  • CVSS Score: 9.1 / 10 (Critical)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:H/VA:H/SC:L/SI:H/SA:L

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


RabbitMQ amqp091-go: Protocol Desynchronization and Frame Injection via Integer Overflow in readLongstr

CVE-2026-77411 / GHSA-c5pq-fr2g-9jpf

More information

Details

Summary

A critical stream desynchronization vulnerability has been identified in the AMQP wire-protocol parser. When parsing a long string (readLongstr) within a table field, providing a length that exceeds the maximum signed 32-bit integer (2^31 - 1, or roughly 2.1 GiB) triggers an improper error-handling condition. The parser abruptly aborts the read and returns a success status ("",nil) without consuming the specified bytes from the underlying network buffer. This causes all subsequent read operations to become misaligned. The parser interprets arbitrary offsets within the remaining payload bytes as valid AMQP frame headers, leading to potential Remote Code Execution (RCE), data injection, or complete connection hijacking.

Vulnerability Details

The vulnerability exists within the bounds-checking logic of the readLongstr function:

// read.go:113-114 — silent no-op return, bytes left in stream
if length > (^uint32(0) >> 1) {
    return  // returns "", nil, does NOT consume `length` bytes
}

When length evaluates to a value greater than 0x7FFFFFFF:

  1. The function executes a silent return statement.
  2. Because Go utilizes named or zero-value initialization for unassigned return registers, this yields "", nil (indicating a successful read of an empty string).
  3. The Critical Failure: The reader's cursor is not advanced by length bytes. The malformed payload remains sitting in the TCP/buffer stream.

Impact

As readTable continues iterating over the stream under the assumption that the string was successfully parsed, the byte alignment is entirely broken.

  • Parser Desynchronization: Future AMQP frame headers are read from arbitrary offsets inside the attacker-controlled message payload.
  • Payload Reinterpretation: A malicious actor can carefully craft the trailing bytes of the initial payload to perfectly mimic valid AMQP frames (e.g., connection.close, channel.open, or message publishing frames), forcing the client/server to execute unintended actions.

Severity

  • CVSS Score: 9.5 / 10 (Critical)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


amqp091-go: Pre-negotiation frame limit is not enforced to 4KB

CVE-2026-107386 / GHSA-w6r9-248c-frg8

More information

Details

Summary

The frame-size mitigation released in amqp091-go v1.13.0 can be bypassed before connection.tune completes. A malicious or compromised AMQP peer can send only a seven-byte body-frame header containing a large attacker-controlled uint32 payload length. The client allocates a slice of that declared length before it verifies that the payload exists or rejects the frame for its invalid protocol state.

The bypass occurs because Connection.maxFrameSize starts at zero. The reader interprets zero as both “negotiated unlimited” and “not negotiated yet,” and skips the pre-allocation size check in either case. Open starts the reader goroutine before negotiation and does not store a limit until after it receives connection.tune.

This remains reachable even if the caller explicitly uses Config{FrameSize: frameMinSize}. A malicious broker can therefore cause excessive memory allocation, potentially terminating the Go client process through memory exhaustion, before authentication and connection setup complete.

Relationship to the existing advisory

GHSA-r9c8-gcjp-xfwh describes attacker-controlled, unbounded allocation by a malicious broker and identifies v1.13.0 as the patched version. Pull request 369 added a frame-size check before parser allocation, but the check is active only when the stored maximum is nonzero.

The v1.13.0 source still:

  1. starts the reader before protocol negotiation;
  2. skips the bound while maxFrameSize == 0;
  3. allocates the body using the peer-declared size; and
  4. stores the negotiated maximum only after connection.tune.

This appears to be an incomplete-fix or state-boundary bypass of the existing advisory rather than an unrelated allocation issue.

Affected source and root cause

The issue was reproduced at commit 9313fd9ea47bdb4e8f7f5db9bef94d5534d0bdde, dated 2026-07-30. The same relevant control flow is in the v1.13.0 tag.

The vulnerable sequence is:

  1. Open starts c.reader(conn) before calling c.open(config).
  2. The reader receives a pointer to the initially zero-valued c.maxFrameSize.
  3. ReadFrame decodes the peer-controlled uint32 size but rejects it only when max > 0.
  4. parseBodyFrame executes make([]byte, size) before io.ReadFull.
  5. maxFrameSize is first stored after processing connection.tune.

The source comments and regression tests explicitly combine “negotiated unlimited” with “not yet negotiated” as the same zero state. Those states need different security behavior.

Safe reproduction

This reproducer does not start RabbitMQ, contact any hosted service, send a large payload, or attempt to crash the process. It declares a 2 MiB body and observes the size of the slice passed to the transport's payload Read. Receiving a 2 MiB destination slice proves that the allocation occurred; the test then releases the blocked read and exits.

  1. Check out v1.13.0.
  2. Save the following as pre_negotiation_frame_limit_test.go in the repository root.
  3. Run go test -run '^TestPreNegotiationFrameLimitBypass$' -count=1 -v ..
package amqp091

import (
	"encoding/binary"
	"io"
	"sync"
	"testing"
	"time"
)

const declaredBodySize = 2 << 20

type stagedFrameConn struct {
	mu          sync.Mutex
	header      []byte
	headerRead  bool
	bodyRead    chan int
	bodyOnce    sync.Once
	release     chan struct{}
	releaseOnce sync.Once
}

func newStagedFrameConn() *stagedFrameConn {
	header := make([]byte, 7)
	header[0] = frameBody
	binary.BigEndian.PutUint16(header[1:3], 1)
	binary.BigEndian.PutUint32(header[3:7], declaredBodySize)
	return &stagedFrameConn{
		header:   header,
		bodyRead: make(chan int, 1),
		release:  make(chan struct{}),
	}
}

func (c *stagedFrameConn) Read(p []byte) (int, error) {
	c.mu.Lock()
	if !c.headerRead {
		c.headerRead = true
		n := copy(p, c.header)
		c.mu.Unlock()
		return n, nil
	}
	c.mu.Unlock()

	c.bodyOnce.Do(func() { c.bodyRead <- len(p) })
	<-c.release
	return 0, io.EOF
}

func (c *stagedFrameConn) Write(p []byte) (int, error) { return len(p), nil }

func (c *stagedFrameConn) Close() error {
	c.releaseOnce.Do(func() { close(c.release) })
	return nil
}

func TestPreNegotiationFrameLimitBypass(t *testing.T) {
	conn := newStagedFrameConn()
	openDone := make(chan error, 1)

	go func() {
		_, err := Open(conn, Config{FrameSize: frameMinSize})
		openDone <- err
	}()

	select {
	case got := <-conn.bodyRead:
		if got != declaredBodySize {
			t.Fatalf("payload Read received a %d-byte slice; want %d", got, declaredBodySize)
		}
	case <-time.After(5 * time.Second):
		t.Fatal("payload Read was not reached")
	}

	_ = conn.Close()
	select {
	case <-openDone:
	case <-time.After(5 * time.Second):
		t.Fatal("Open did not exit after the test connection closed")
	}
}
Expected secure behavior

The pre-negotiation reader rejects the oversized declared frame before allocating its payload buffer. The transport should never receive a payload Read with a 2 MiB destination slice.

Actual behavior

The test passes because the transport receives a payload Read whose destination slice is exactly 2 MiB, despite the caller setting Config.FrameSize to frameMinSize. This slice was created by make([]byte, size) using the untrusted frame header.

Additional local validation

A five-test differential harness was run against the exact tested commit. All tests passed:

=== RUN   TestCounterfactualZeroFrameLimitAllocatesBeforePayloadRead
--- PASS: TestCounterfactualZeroFrameLimitAllocatesBeforePayloadRead
=== RUN   TestCounterfactualNegotiatedLimitRejectsBeforePayloadAllocation
--- PASS: TestCounterfactualNegotiatedLimitRejectsBeforePayloadAllocation
=== RUN   TestCounterfactualZeroLimitAllowsSmallFrameControl
--- PASS: TestCounterfactualZeroLimitAllowsSmallFrameControl
=== RUN   TestCounterfactualNegotiatedLimitAllowsSmallFrameControl
--- PASS: TestCounterfactualNegotiatedLimitAllowsSmallFrameControl
=== RUN   TestCounterfactualPublicOpenReachesZeroLimitAllocation
--- PASS: TestCounterfactualPublicOpenReachesZeroLimitAllocation
PASS
ok github.com/rabbitmq/amqp091-go 0.907s

The controls establish that:

  • the zero pre-negotiation state reaches attacker-sized allocation;
  • a frameMinSize bound rejects the same declaration before allocation;
  • both states continue to accept a valid small frame; and
  • the vulnerable state is reachable through public Open, not only through an internal helper.
Impact

The frame body length is a network-controlled 32-bit unsigned integer, so one seven-byte frame header can request an allocation approaching 4 GiB on a 64-bit client. The attacker does not need to transmit the declared body before allocation occurs. On memory-constrained clients or containers, this can cause severe memory pressure, an out-of-memory condition, or process termination.

The required attacker position is a malicious or compromised broker, or an equivalent peer able to provide the AMQP transport during connection establishment. No application credentials, user interaction, confidentiality impact, or integrity impact is required or claimed. The primary impact is availability of the client process and potentially dependent services.

Protocol relevance

The AMQP 0-9-1 reference requires peers to accept frames up to the 4096-byte frame-min-size before frame-max is negotiated. It does not require accepting arbitrarily large pre-negotiation frames. A provisional 4096-byte receive limit is therefore compatible with the stated pre-negotiation requirement.

Suggested remediation

Represent these states separately:

  • pre-negotiation, with a provisional frameMinSize receive bound;
  • negotiated with a finite frame_max; and
  • explicitly negotiated unlimited, if that behavior remains supported.

Initialize the provisional bound before the reader goroutine starts, then replace it with the negotiated result after connection.tune. Reject any declared payload that would make the total frame exceed the active limit before calling a frame parser or allocating a payload buffer. A protocol-state check that rejects body frames before connection setup completes would add defense in depth.

Please add a regression through public Open that sends an oversized body-frame header before connection.tune and verifies rejection before payload allocation, while retaining small valid-frame controls.

Severity

  • CVSS Score: 6.3 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

rabbitmq/amqp091-go (github.com/rabbitmq/amqp091-go)

v1.14.0

Compare Source

Full Changelog

Fixed bugs:

  • fix: preserve caller-provided SASL credentials across Reconnect() #​389 (suchitd)
  • fix: clone SASL authentication before zeroing credentials post-handshake #​388 (suchitd)

Closed issues:

  • v1.13.0 (#​350) zeroes caller-provided PlainAuth.Password, breaking auth on any reconnect that reuses the Config #​387

Merged pull requests:

  • chore(deps): bump github/codeql-action from 4.37.8 to 4.37.9 in the github-actions group #​390 (dependabot[bot])
  • chore(deps): bump github/codeql-action from 4.37.7 to 4.37.8 in the github-actions group #​386 (dependabot[bot])
  • chore(deps): bump github/codeql-action from 4.37.6 to 4.37.7 in the github-actions group #​385 (dependabot[bot])

v1.13.0

Compare Source

Full Changelog

Implemented enhancements:

Fixed bugs:

Closed issues:

  • DialConfig leaks a watchConnection goroutine when the AMQP handshake fails with Recovery enabled #​408
  • panic: unexpected frame type #​400
  • v1.13.0: openComplete() zeroes caller-owned SASL credentials, breaking Config reuse across dials #​394
  • Dial returns 403 "no access to this vhost" when the broker refuses connection.open with 530 NOT_ALLOWED (e.g. user connection limit reached) #​392
  • Question mark in password breaks connection string parsing #​305

Merged pull requests:

v1.12.0

Compare Source

Full Changelog

Implemented enhancements:

  • feat: skip-and-continue topology recovery with per-entity error surfacing #​365 (suchitd)
  • Make TopologyRecoveryAllEnabled the default topology recovery mode #​362 ([

[!IMPORTANT]
✂ PR body was truncated to here.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate
renovate Bot force-pushed the renovate/go-github.com-rabbitmq-amqp091-go-vulnerability branch from 38e17d4 to 634ae61 Compare October 16, 2026 06:43
@renovate renovate Bot changed the title fix(deps): update module github.com/rabbitmq/amqp091-go to v1.13.0 [security] fix(deps): update module github.com/rabbitmq/amqp091-go to v1.14.0 [security] Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants