← All write-ups
December 5, 2025HIGHCLIENT FINDING

XML entity expansion denial of service in upload processing

2025 · Client Q · Web, API & enterprise software

Sanitized finding from Client Q. The original product, endpoint and payload are omitted.

Context

The application accepted XML-like business data through an upload endpoint. The request body was wrapped by the application protocol before server-side parsing.

Finding

Recursive entity expansion and malformed declaration patterns caused disproportionate CPU and memory consumption. Repeated requests produced processing errors and degraded service responsiveness, indicating that parser limits and entity resolution controls were not enforced at the trust boundary.

Technical workflow

The behavior was reproduced with sanitized local fixtures and one request at a time. The endpoint below is intentionally a placeholder:

curl --fail-with-body --max-time 5 \
  -H 'Content-Type: application/xml' \
  --data-binary @fixtures/bounded.xml \
  'https://AUTHORIZED_HOST/api/import'

The application-side parser should use a hardened implementation and reject DTDs or external entities unless the business case explicitly requires them:

from defusedxml.ElementTree import parse

def parse_untrusted_xml(path: str):
    # defusedxml blocks common entity-expansion and external-entity classes.
    return parse(path)

This is only one layer. The service also needs byte, node, expansion-ratio and wall-clock budgets, plus a request body limit before parsing. During retest I correlated response time with CPU, memory, parser errors and worker restarts.

Impact

An unauthenticated or low-privilege remote caller could consume application resources and interrupt normal processing. The issue also increases operational cost and can amplify the effect of burst traffic.

Remediation

Validation

Re-test with bounded and recursive entity cases while monitoring CPU, memory, latency and process stability. The service should reject unsafe input quickly and consistently.

Expected result: a deterministic 4xx response, no external resolution, no worker restart and a rate-limit/security event for repeated rejected documents.