Skip to content

ELB classic load balancers should be configured with defensive or strictest desync mitigation mode

HTTP desync attacks send ambiguous requests that a load balancer and backend parse differently, letting an attacker smuggle requests, poison caches, or hijack other users' sessions. The "monitor" mode only emits CloudWatch metrics without blocking anything, so backends are fully exposed.

Setting the mode to "defensive" (the AWS default) or "strictest" causes the Classic Load Balancer to actively modify or reject requests that violate RFC 7230. "Strictest" drops any ambiguous request outright, which can break poorly behaved clients but provides the strongest protection.

Retrofit consideration

Switching from "monitor" to "strictest" may reject legitimate but non-conformant HTTP requests from older clients. Apply to a non-production environment first via a separate terraform apply targeting that workspace. If you see unexpected 400s, "defensive" is the safer intermediate step.

Implementation

Choose the approach that matches how you manage Terraform.

Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.

module "elb" {
  source  = "pcidss.compliance.tf/terraform-aws-modules/elb/aws"
  version = ">=4.0.0,<5.0.0"

  health_check = {
    healthy_threshold   = 2
    interval            = 30
    target              = "HTTP:80/"
    timeout             = 5
    unhealthy_threshold = 2
  }
  internal = true
  listener = [
    {
      instance_port     = 80
      instance_protocol = "HTTP"
      lb_port           = 80
      lb_protocol       = "HTTP"
    }
  ]
  name            = "abc123"
  security_groups = ["sg-abc12345"]
  subnets         = ["subnet-abc123", "subnet-def456"]
}

module "elb" {
  source  = "acscessentialeight.compliance.tf/terraform-aws-modules/elb/aws"
  version = ">=4.0.0,<5.0.0"

  health_check = {
    healthy_threshold   = 2
    interval            = 30
    target              = "HTTP:80/"
    timeout             = 5
    unhealthy_threshold = 2
  }
  internal = true
  listener = [
    {
      instance_port     = 80
      instance_protocol = "HTTP"
      lb_port           = 80
      lb_protocol       = "HTTP"
    }
  ]
  name            = "abc123"
  security_groups = ["sg-abc12345"]
  subnets         = ["subnet-abc123", "subnet-def456"]
}

module "elb" {
  source  = "pcidssv321.compliance.tf/terraform-aws-modules/elb/aws"
  version = ">=4.0.0,<5.0.0"

  health_check = {
    healthy_threshold   = 2
    interval            = 30
    target              = "HTTP:80/"
    timeout             = 5
    unhealthy_threshold = 2
  }
  internal = true
  listener = [
    {
      instance_port     = 80
      instance_protocol = "HTTP"
      lb_port           = 80
      lb_protocol       = "HTTP"
    }
  ]
  name            = "abc123"
  security_groups = ["sg-abc12345"]
  subnets         = ["subnet-abc123", "subnet-def456"]
}

If you use terraform-aws-modules/elb/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "elb" {
  source  = "terraform-aws-modules/elb/aws"
  version = ">=4.0.0,<5.0.0"

  health_check = {
    healthy_threshold   = 2
    interval            = 30
    target              = "HTTP:80/"
    timeout             = 5
    unhealthy_threshold = 2
  }
  internal = true
  listener = [
    {
      instance_port     = 80
      instance_protocol = "HTTP"
      lb_port           = 80
      lb_protocol       = "HTTP"
    }
  ]
  name            = "abc123"
  security_groups = ["sg-abc12345"]
  subnets         = ["subnet-abc123", "subnet-def456"]
}

Use AWS provider resources directly. See docs for the resources involved: aws_elb.

resource "aws_elb" "this" {
  internal = true

  listener {
    instance_port     = 80
    instance_protocol = "http"
    lb_port           = 80
    lb_protocol       = "http"
  }

  subnets = ["subnet-abc123", "subnet-def456"]

  desync_mitigation_mode = "defensive"
}

What this control checks

The policy evaluates desync_mitigation_mode on every aws_elb resource. The argument takes three values: "monitor", "defensive", and "strictest". Setting it to "defensive" or "strictest" passes; "monitor" fails. If the argument is omitted, Terraform defaults to "defensive", which also passes.

Common pitfalls

  • Default value masks explicit intent

    Omitting desync_mitigation_mode passes the check today because Terraform defaults to "defensive". But if someone changes the attribute directly via the console or CLI, the drift is silent until the next terraform plan or Config evaluation catches it. Set the value explicitly in every resource block.

  • Strictest mode can break non-conformant clients

    Setting desync_mitigation_mode = "strictest" rejects any request that doesn't strictly conform to RFC 7230. Applications receiving traffic from legacy systems, IoT devices, or HTTP libraries that send malformed headers such as duplicate Content-Length will start returning 400 errors. Check the DesyncMitigationMode_NonCompliant_Request_Count CloudWatch metric before making the switch.

  • Control applies only to Classic Load Balancers

    This check only covers aws_elb (Classic Load Balancer). Application Load Balancers (aws_lb with load_balancer_type = "application") have their own desync_mitigation_mode argument and are covered by a separate control. Passing this check says nothing about your ALBs.

Audit evidence

Auditors typically want AWS Config rule evaluation results showing all Classic Load Balancers pass the desync mitigation check. The CLI command aws elb describe-load-balancer-attributes --load-balancer-name <name> returns DesyncMitigationMode under AdditionalAttributes as point-in-time evidence. Console screenshots from the EC2 Load Balancers page, showing the attribute under the Description tab, are also acceptable.

For continuous compliance, AWS Config conformance pack reports or CSPM findings filtered to this control show ongoing enforcement rather than a single snapshot.

Framework-specific interpretation

PCI DSS v4.0: Requirement 6.2.1 calls for software attack prevention as part of secure development practices. HTTP request smuggling falls squarely in that category. Setting mitigation to defensive or strictest reduces exposure at the load balancer layer for cardholder data environments running behind Classic ELBs.

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: elb_classic_lb_desync_mitigation_mode

  • AWS Config Managed Rule: CLB_DESYNC_MODE_CHECK

  • Checkov Check: CKV_AWS_328

  • Powerpipe Control: aws_compliance.control.elb_classic_lb_desync_mitigation_mode

  • Prowler Check: elb_desync_mitigation_mode

  • AWS Security Hub Control: ELB.14

Last reviewed: 2026-03-09