# UNDF: UNDF-2026-000000353
## Classification

| Field       | Value |
|-------------|-------|
| CWE         | CWE-407 Inefficient Algorithmic Complexity |
| Severity    | MEDIUM |
| Component   | `artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/BindingsImpl.java:639` |
| Function    | `BindingsImpl.routeFromCluster()` |
| Hot path    | Called per cluster message delivery — fires on every message routed in a cluster node |
| Status      | PATCHED (unit test PASS) |

## Defect

`routeFromCluster()` decodes `HDR_ROUTE_TO_ACK_IDS` into a `List<Long>` then uses
`List.contains()` inside the main routing loop:

```java
// Build ack-IDs list from byte buffer — O(M)
List<Long> idsToAckList = new ArrayList<>();
if (idsToAck != null) {
    ByteBuffer buff = ByteBuffer.wrap(idsToAck);
    while (buff.hasRemaining()) {
        idsToAckList.add(buff.getLong());         // add each ack ID
    }
}

// Route each binding ID — O(N×M) due to List.contains
ByteBuffer buff = ByteBuffer.wrap(ids);
while (buff.hasRemaining()) {
    long bindingID = buff.getLong();
    Binding binding = bindingsIdMap.get(bindingID);
    if (binding != null) {
        if (idsToAckList.contains(bindingID)) {  // O(M) per binding
            binding.routeWithAck(message, context);
        } else {
            binding.route(message, context);
        }
    }
}
```

With N=100 binding IDs and M=50 ack IDs: **5,000 comparisons per cluster message**,
repeated for every message with cluster routing IDs.

## Fix

Use `Set<Long>` instead of `List<Long>`:

```java
Set<Long> idsToAckSet = new HashSet<>();
if (idsToAck != null) {
    ByteBuffer buff = ByteBuffer.wrap(idsToAck);
    while (buff.hasRemaining()) {
        idsToAckSet.add(buff.getLong());          // O(1) insert
    }
}

ByteBuffer buff = ByteBuffer.wrap(ids);
while (buff.hasRemaining()) {
    long bindingID = buff.getLong();
    Binding binding = bindingsIdMap.get(bindingID);
    if (binding != null) {
        if (idsToAckSet.contains(bindingID)) {    // O(1)
            binding.routeWithAck(message, context);
        } else {
            binding.route(message, context);
        }
    }
}
```

Speedup: ~50× at N=100, M=50 (5,000 → 100 effective operations).
