Safeguard
Application Security•

CWE-606: Unchecked Input Used as a Loop Condition

When a packet or request decides how many times a loop runs, a crafted value can pin a CPU. How CWE-606 shows up in parsers and what to do about it.

Safeguard Security Team
2 min read

CWE-606 is a plain-sounding weakness: inputs used for loop conditions are not properly checked, which can lead to denial of service or other consequences through excessive looping.

It is common in protocol parsers, file format readers, and anything that reads a count from the wire and then repeats work that many times.

How it happens

A message carries a length or count field. The code trusts it.

# Vulnerable pattern
def parse(packet):
    count = int.from_bytes(packet[0:4], "big")
    items = []
    for i in range(count):          # attacker picks count
        items.append(read_item(packet))
    return items

A tiny packet can claim four billion items. Or the condition might depend on a value that never reaches the exit state, which produces an infinite loop.

MITRE's observed example is CVE-2025-32399, a chain in which a library for implementing Profinet devices did not check an input for a loop condition, allowing an infinite loop through a crafted RPC packet.

What an attacker gains

The recorded impact is availability, specifically resource consumption on the CPU. One cheap request can keep a thread or a whole device busy. On embedded and industrial devices, that can take a service offline.

How to find it

Static analysis (SAST) can find some instances by tracing external inputs into loop bounds. For a hands-on check, send protocol messages with maximum, zero, and negative counts and watch CPU use and response time. Fuzzing the parser is a natural fit.

How to fix it

MITRE gives two steps.

  1. Do not use user-controlled data directly for loop conditions.
  2. Perform input validation.

In practice, clamp counts to a sane maximum, compare the claimed count with the bytes that remain, and add an overall time or iteration budget.

MAX_ITEMS = 1000
def parse(packet):
    count = int.from_bytes(packet[0:4], "big")
    if count > MAX_ITEMS or count * ITEM_SIZE > len(packet) - 4:
        raise ValueError("bad count")
    return [read_item(packet) for _ in range(count)]

Quick check

What is the cheapest sanity check on a claimed count? Compare it with the number of bytes actually received. A count that cannot fit in the remaining data is invalid.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.