unbridled-41 opened a new issue, #2832:
URL: https://github.com/apache/rocketmq-dashboard/issues/2832

   ## Problem
   
   PR #2339 added a broker-topology guard (`validatedBrokerAddr`) that rejects 
offset message ids whose decoded broker address is outside the selected 
instance topology. However, the guard only covers the **fallback** path 
(`viewMessageByOffsetId`). The **primary** lookup path still invokes 
`adminExt.viewMessage(topic, msgId)` with no address validation, and it runs 
**before** the fallback — so a forged offset msgId still makes Studio open a 
RocketMQ remoting connection to an attacker-chosen `ip:port`.
   
   ## Evidence
   
   
`server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProvider.java`:
   
   - Line 146 (`queryByMsgId`) and line 570 (`resolveMessageStoreTimestamp`) 
call `adminExt.viewMessage(topic, msgId)` directly, before any validation.
   - The guarded fallback (`viewMessageByOffsetId`, `validatedBrokerAddr`) is 
only reached when the primary call throws or returns null.
   
   What the client does with that call (verified in the rocketmq 5.5.x 
bytecode):
   
   `MQAdminImpl.viewMessage(topic, msgId)` -> 
`MessageDecoder.decodeMessageId(msgId)` -> 
`MQClientAPIImpl.viewMessage(NetworkUtil.socketAddress2String(messageId.getAddress()),
 topic, offset, ...)`
   
   `decodeMessageId` builds a literal `InetSocketAddress` from bytes 0-7 of a 
32-char hex offset id (`InetAddress.getByAddress` — no DNS), so the caller 
fully controls both IP and port. The existing fallback test 
(`queryByMsgIdRejectsDecodedBrokerOutsideKnownTopology`) stubs `viewMessage` to 
throw, which is why the guard test passes while the production primary path 
still connects first.
   
   The codebase itself acknowledges this bug class in `ToolAccessPolicy.java`:
   
   > These read-labeled tools still let callers steer RocketMQ remoting to 
user-influenced broker addresses via msgId-derived lookups, so readers must not 
gain access before the address-ownership validation bug is fixed.
   
   The AI tool route is deny-listed for readers, but the REST routes `GET 
/api/messages` (query by msgId) and `GET /api/messages/{msgId}/trace` are 
reader-accessible and reach the identical unguarded sink.
   
   ## Impact
   
   Any authenticated reader-role user can make Studio open RocketMQ remoting 
connections to arbitrary internal `ip:port` endpoints (blind SSRF / port-scan 
oracle via timing and error text). Against a broker address of a *different* 
instance, the primary path returns that broker's message content — a 
cross-instance message read.
   
   ## Suggested fix
   
   Decode the msgId and validate the embedded address with the existing 
`validatedBrokerAddr` helper **before** invoking `adminExt.viewMessage(topic, 
msgId)` in both `queryByMsgId` and `resolveMessageStoreTimestamp`. Ids that do 
not decode as offset ids can pass through untouched — `MQAdminImpl` falls back 
to the unique-key lookup, which resolves brokers from the topic route and is 
not steerable by the id.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to