Summary

  • RFC 5393 documented how fewer than ten valid SIP messages could set up a request tree with a potential 2^71 messages; even universal loop detection leaves a multi-AOR construction with more than N! traffic before paths repeat.
  • Max-Breadth caps concurrent branches and allows completed breadth to be reused. It reduces the instantaneous state and bandwidth peak, but the RFC explicitly says it does not reduce aggregate attack traffic.
  • Safe operation needs separate receipts for routing inputs, Via history, loop-versus-spiral decisions, active breadth, cumulative branches and history preserved across gateways or B2BUAs.

The fifth branch waited; it did not disappear

Concurrency controls are attractive because they produce a clean number. A dashboard can show four active branches against a limit of four. Memory remains below a threshold. The node avoids opening the fifth transaction while all four permits are occupied. The picture is accurate and incomplete.

RFC 5393 defines Incoming Max-Breadth for a response context and Outgoing Max-Breadth as the sum assigned to forwarded requests that have not yet received a final response. The outgoing sum must not exceed the incoming value. Once a branch receives its final response, its allocation no longer counts and becomes available for reuse.

The standard's example is deliberately simple. A proxy has eight targets and receives breadth four. It initially opens four branches with one unit each. When one fails, the active sum falls to three. The proxy can then use the returned unit for a fifth target. Repetition can visit all eight destinations while the concurrent count never exceeds four.

That is not a defect hidden in an implementation. Reclamation is part of the design. The rejected alternative—never reuse breadth—would have imposed a constant lifetime multiplier, but the working group believed it would change legitimate reach so sharply that existing deployments could break. RFC 5393 chose a bounded peak and preserved serial exploration.

An executive report that says “forking is limited to four” therefore needs a noun after “limited.” Four active branches? Four targets for the life of the request? Four hops? Four attempts per identity? The protocol answers only the first. Omitting the denominator turns a correct control into a false assurance.

A few valid messages built a binary request tree

The vulnerability began in ordinary SIP registration and proxy behavior. Two proxy/registrar services held four Addresses of Record. Each AOR at the first service registered both AORs at the second as contacts, and the second registered the two at the first. An INVITE to one AOR forked into two requests, those forked into four, then eight.

Nothing in the initial setup had to be a malformed packet. The multiplier came from valid bindings combined with recursive forking. Requests continued until Max-Forwards reached zero. At the RFC 3261 recommended starting value of 70, the binary tree contains 2^71 - 1 requests. If processing lasts beyond Timer C, CANCEL and 408 traffic can add another storm while each proxy holds transaction state.

The introduction summarizes the attack more starkly: fewer than ten messages can stimulate potentially 2^71 messages. This is a potential count for the documented construction, not a measurement of the public Internet. Its value is architectural. Input validity, account authentication and per-message correctness do not bound the graph a valid message is allowed to create.

RFC 5393 reports that the attack was realized at a SIP Interoperability Test session. With more than two proxies and Max-Forwards capped at 20, the participants bombarded one another for hours. The RFC extrapolated completion of the initiating INVITE to just under ten days. Some proxies rebooted and rejoined when their registration state survived. Restart restored execution without removing the authority encoded in the routing graph.

That observation separates process health from system recovery. A restarted service can be locally clean and immediately resume harmful work because the durable registrations that created the work remain valid. Recovery needs a receipt for the causal state, not just a new process identifier.

Loop detection fixed one graph, not every graph

For the simple alternating setup, loop detection changes the outcome decisively. RFC 5393 says detection at any participating proxy stops the attack immediately; if all proxies implement it, the first scenario falls to 14 stimulated messages and the one-server variation to 10.

The normative update therefore requires a proxy that forks to more than one location to ensure that the request is not looping through that proxy. The refined Via branch value has a second part derived from the Request-URI, relevant Route fields and every other input used by location-service logic. When the proxy sees its own prior marker again, it recomputes that part. Equal values mean the routing inputs are unchanged: reject with 482. Different values mean the request has spiraled through the node under changed routing context, so processing may continue.

Loop and spiral are not stylistic labels. They decide whether recurrence is evidence of useless repetition or a legitimate new stage. If the identity ignores a field that actually changes forwarding, a valid spiral may be killed. If it includes a field that changes on every pass without affecting forwarding, a loop may look new forever.

The algorithm also creates an evidence dependency. A downstream proxy can detect recurrence only because earlier Via branch parameters remain intact. RFC 5393 warns that removing, obfuscating or modifying those parameters takes away the originating node's ability to recognize the loop. If two nodes on the path erase the evidence, neither can detect what they have jointly concealed.

Ten AORs defeat the comforting loop story

The stronger construction uses N AORs, each configured to fork to the full set. Begin at AOR 1. Before any AOR repeats, every permutation of the other N-1 AORs can be traversed. Each such path then forks N ways once more and finally triggers loop detection. The last layer alone contains N! requests.

RFC 5393's table makes the curve concrete. One AOR produces one forwarded request. Four produce 64. Six produce 1,956. Eight produce 109,600. Ten produce 9,864,100. The document states that when N does not exceed Max-Forwards, total traffic is greater than N! even if every proxy detects loops.

This does not make every SIP deployment factorial. It identifies a blind spot in the claim “we turned on loop detection.” A control that recognizes repetition cannot prevent the combinatorial number of distinct histories that occur before repetition. The path is new according to the very evidence needed to avoid false positives.

The governance lesson is precise. Identity controls bound duplicate work; they do not automatically bound novel combinations. A directory, workflow engine or retry graph can obey every local uniqueness check while generating an unacceptable number of unique paths. Total-work policy needs its own ledger.

Max-Forwards, Max-Breadth and lifetime work govern different axes

Max-Forwards limits hop depth. RFC 5393 explicitly forbids treating Max-Breadth as another hop counter. A proxy must not decrement breadth at each hop merely to restrict propagation distance. The two fields answer orthogonal questions: how far may one path travel, and how many branches may be active at once?

The 440 Max-Breadth Exceeded response appears when a proxy cannot fit its desired parallel fork into the received budget and is unwilling or unable to use serial forking or redirection. A breadth of one still allows sequential forks. Receiving 440 proves that one parallel plan was refused; it does not prove the request stopped exploring other targets or that aggregate traffic fell.

This separation matters for measurement. A system can have stable active concurrency while cumulative branches, hop count and elapsed transaction time continue rising. It can have a shallow path with explosive breadth, or one serial branch that travels a great distance. A single “amplification protected” badge erases which axis was actually controlled.

The right operational record has at least three counters: current active breadth per response context, cumulative branches opened during that context, and maximum/actual hop depth per branch. It also needs the count of initiating requests, because an attacker can send many separately valid roots and gradually fill the network despite each root observing its own breadth cap.

Slowing the flood creates time for intervention, not proof of prevention

RFC 5393 is unusually direct in its security section. Max-Breadth does not decrease aggregate traffic from the forking-loop attack. It spreads that traffic over a longer period by limiting how many branches are processed simultaneously. Multiple requests can still build traffic to unreasonable levels.

The benefit is real. Lower instantaneous state and bandwidth can keep nodes alive long enough for operators to identify the implicated resources and intervene. A fast increase in outstanding transactions system-wide can expose a distributed construction; a gradual increase associated with one resource can expose a narrower one. The standard advises monitoring both and being able to disable resources temporarily.

But time to act is an operational option, not an automatic outcome. A rate-limited attack that runs unnoticed for days can consume more aggregate work than a visible burst that is stopped in minutes. Conversely, a strict lifetime cap can destroy legitimate reach if it prevents serial contact attempts that users depend upon. The standard leaves that economic choice outside a single header.

This is the same discipline Heng Lu describes as a minimum initial specification. The shared protocol defines a narrow budget that interoperable actors can enforce. It does not pretend to own each operator's target ordering, account suspension, incident threshold or acceptable lifetime cost. Local authority remains—but so does the obligation to measure what the common primitive does not guarantee.

A gateway can erase the evidence while preserving the work

Protocol translation is the hardest boundary. A SIP request can enter the public switched telephone network and later return to SIP. A B2BUA terminates one SIP leg and originates another. If the element discards the prior request history, Max-Forwards and Via-based loop detection may no longer describe one continuous journey.

RFC 5393 warns that forking amplification combined with such lost history can create a loop that its mechanisms do not even limit to a bounded number of concurrent messages. Topology hiding supplies a commercial and security incentive to remove exactly the evidence on which distributed safeguards rely. If two such boundaries each assume they can detect recurrence privately, neither sees the whole circuit.

RFC 7332 later imposed clearer behavior. B2BUAs must copy and decrement Max-Forwards, copy and enforce Max-Breadth across their UAS and UAC sides, and are recommended to implement RFC 5393 loop detection. It also states the trade-off plainly: administrators may value obfuscation or loop detection, but resetting the fields is at odds with the standard behavior.

Header presence is still not running-code proof. An operator needs to test a request across the actual B2BUA, confirm the values and history that emerge, and observe whether parallel requests on the far side share the incoming budget. A configuration claim or product sheet cannot substitute for a captured execution trace.

Evidence boundary

The frozen sources establish RFC text, status, the SIPit account recorded by the RFC, the stated examples and later normative B2BUA requirements. They do not establish which current carrier, vendor or enterprise implements the controls, how frequently the attack occurs, or whether any recent outage had this cause.

2^71, N! and 9,864,100 must remain attached to their constructions. They are not generic SIP traffic forecasts. Likewise, a low active-branch chart cannot be presented as evidence of low cumulative work without a lifetime counter.

The durable conclusion is narrower. A concurrency limit is a photograph of work in progress. Safety also needs the ledger: which identities created branches, which history allowed them, how many branches completed, how often breadth was returned, how far paths travelled and whether any user outcome justified the effort.