Skip to main content
emnode
Compliance Medium severity

AWS Security Hub · ELB

ELB.4: ALB accepts malformed HTTP headers

Written and reviewed by Emnode · Last reviewed

What does AWS Security Hub ELB.4 check?

ELB.4 fails when an Application Load Balancer has the drop_invalid_header_fields attribute set to false. With the attribute off, the ALB forwards requests whose headers contain characters that are not valid per the HTTP spec.

Why does ELB.4 matter?

When a front-end load balancer and a back-end target disagree on where one request ends and the next begins, an attacker can smuggle a hidden request inside a malformed Content-Length or Transfer-Encoding header (HTTP desync). That can poison caches, bypass auth on the front end, or hijack another user's session. Dropping invalid headers removes the ambiguity the attack depends on.

How do I fix ELB.4?

  1. Audit each ALB with describe-load-balancer-attributes and check routing.http.drop_invalid_header_fields.enabled.
  2. Set it to true with modify-load-balancer-attributes; the change is non-disruptive to well-formed traffic.
  3. Enable ELB.5 (access logs) alongside this for a hardened perimeter; if you instead enforce ELB.12 (defensive or strictest desync mitigation mode), AWS recommends disabling ELB.4, since ELB.12 supersedes it for HTTP desync protection.
  4. Default the attribute on in your IaC so new ALBs are compliant from creation.

Remediation script · bash

# Harden every Application Load Balancer in the region: reject invalid headers and
# require defensive (or strictest) desync mode. Both are instant, non-disruptive flips.
for arn in $(aws elbv2 describe-load-balancers \
    --query 'LoadBalancers[?Type==`application`].LoadBalancerArn' --output text); do
  aws elbv2 modify-load-balancer-attributes --load-balancer-arn "$arn" \
    --attributes \
      Key=routing.http.drop_invalid_header_fields.enabled,Value=true \
      Key=routing.http.desync_mitigation_mode,Value=defensive
  echo "$arn: hardened"
done

# Switch load-balanced Auto Scaling groups to ELB health checks with a safe grace period
# (confirm the target-group probe reflects real app health first).
for g in $(aws autoscaling describe-auto-scaling-groups \
    --query 'AutoScalingGroups[?(LoadBalancerNames!=`[]` || TargetGroupARNs!=`[]`) && HealthCheckType==`EC2`].AutoScalingGroupName' \
    --output text); do
  aws autoscaling update-auto-scaling-group --auto-scaling-group-name "$g" \
    --health-check-type ELB --health-check-grace-period 300
  echo "$g: now using ELB health checks"
done

Full walkthrough (console steps, edge cases and verification) in the lesson Harden load balancers (ALB/NLB/CLB).

Is ELB.4 a false positive?

ELB.4 fails whenever drop_invalid_header_fields is off, but AWS explicitly recommends disabling this control if ELB.12 is enabled in your account. ELB.12 requires the ALB to run in defensive or strictest desync mitigation mode, which already neutralises the HTTP desync class that dropping invalid headers guards against, so an ALB that fails ELB.4 yet passes ELB.12 is correctly hardened, not exposed. Rather than suppressing per-resource, disable the ELB.4 control in accounts where ELB.12 is enforced (and conversely keep ELB.4 on where you've chosen not to require defensive desync mode), so the standard reflects your actual, documented mitigation strategy.

Part of the learning path Build in resilience
  • ELB.1 ALB serves HTTP without redirecting to HTTPS
  • ELB.2 CLB SSL/HTTPS listeners should use ACM certs
  • ELB.3 CLB listeners should use HTTPS/TLS termination
  • ELB.5 Load balancers are not writing access logs
  • ELB.6 Load balancers can be deleted by accident
  • ELB.7 CLBs should have connection draining
  • ELB.8 CLB SSL listeners should use strong policy
  • ELB.9 CLBs should have cross-zone balancing
  • ELB.10 CLBs should span multiple AZs
  • ELB.12 ALB desync mitigation mode
  • ELB.13 A single-AZ load balancer is a data-plane single point of failure
  • ELB.14 CLB desync mitigation mode