Skip to content

[Bug] V1 retry topic name collisions can cause cross-topic consumption and message mix-up #9633

@KingCide

Description

@KingCide

Before Creating the Bug Report

  • I found a bug, not just asking a question, which should be created in GitHub Discussions.

  • I have searched the GitHub Issues and GitHub Discussions of this repository and believe that this is not a duplicate.

  • I have confirmed that this bug belongs to the current repository, not other repositories of RocketMQ.

Runtime platform environment

MacOS 15.1

RocketMQ version

5.3.3

JDK Version

1.8

Describe the Bug

  • Under V1 retry topic naming (%RETRY%group_topic), different (topic, consumerGroup) pairs may map to the same retry topic name. When this happens, messages retried from one topic/group can be consumed by another topic/group that shares the same V1 retry topic name, causing cross-topic consumption and potential data leakage.

Root cause

  • V1 retry topic naming (%RETRY%group_topic) loses information and is not one-to-one. Different combinations can collide, e.g., (Order_Topic, MyConsumerGroup) and (Topic, MyConsumerGroup_Order).
  • The broker routes retried messages based solely on the retry topic name, so collisions merge streams.

Steps to Reproduce

  1. Create two topic/group pairs:
  • Pair A: topic = Order_Topic, group = MyConsumerGroup
  • Pair B: topic = Topic, group = MyConsumerGroup_Order
  1. Both pairs map to the same V1 retry topic: %RETRY%MyConsumerGroup_Order_Topic.
  2. Use POP remoting push consumer.
  3. Produce and consume messages on Order_Topic; do not ACK some messages so they enter %RETRY%MyConsumerGroup_Order_Topic.
  4. Switch the consumer subscription to topic=Topic, group=MyConsumerGroup_Order (Pair B).
  5. Observe that the consumer receives many retry messages from the shared V1 retry topic that actually originated from Order_Topic (Pair A). msg.getTopic() shows Topic, but the message body proves the origin was Order_Topic.

What Did You Expect to See?

Retry queues should be isolated per original (topic, group). A consumer on Pair B must not receive retry messages originating from Pair A.

What Did You See Instead?

Due to the non-injective V1 retry naming scheme, both pairs share the same retry topic name; consumers of one pair can receive retry messages from the other.

Log Evidence:

[RETRY] Topic: Topic, QueueId: 0, ReconsumeTimes: 1, Content: Hello world, this is from Order_Topic
    timestamp: 2025-08-23 17:30:37,378
    ...
[RETRY] Topic: Topic, QueueId: 0, ReconsumeTimes: 1, Content: Hello world, this is from Order_Topic
    timestamp: 2025-08-23 17:30:37,378
    ...

This demonstrates a critical message routing and security flaw.

Additional Context

Impact

  • Message correctness violation and potential data leakage across tenants or applications.
  • Hard-to-diagnose behavior because msg.getTopic() reflects the consumer’s current topic, masking the real source unless the payload carries explicit markers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions