Skip to content

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

HTTP desync (request smuggling) attacks exploit inconsistencies in how front-end proxies and back-end servers parse HTTP requests. An attacker who can smuggle a crafted request past the ALB can poison connection pools, hijack other users' sessions, or bypass security controls entirely. The "monitor" mode emits CloudWatch metrics for suspect requests but still forwards them, leaving back-end targets fully exposed.

Setting the mode to "defensive" causes the ALB to normalize known-ambiguous requests before routing. That stops most desync vectors with minimal application impact. The "strictest" mode goes further by rejecting any request that doesn't fully comply with RFC 7230. It may break some legacy clients, but it eliminates the attack surface almost entirely.

Retrofit consideration

Switching from "monitor" to "strictest" may reject legitimate but non-compliant HTTP requests from older clients. Test with "defensive" first and review the DesyncMitigationMode_NonCompliant_Request_Count metric before tightening.

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 "alb" {
  source  = "nistcsfv11.compliance.tf/terraform-aws-modules/alb/aws"
  version = ">=10.0.0,<11.0.0"

  access_logs = {
    bucket  = "example-bucket-abc123"
    enabled = true
  }
  internal = true
  listeners = {
    https = {
      certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
      forward = {
        target_group_key = "default"
      }
      protocol   = "HTTPS"
      ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
    }
  }
  load_balancer_type = "application"
  name               = "abc123"
  security_groups    = ["sg-abc12345"]
  subnets            = ["subnet-abc123", "subnet-def456"]
  target_groups = {
    default = {
      create_attachment = false
      name_prefix       = "def-"
      port              = 443
      protocol          = "HTTPS"
      target_type       = "ip"
    }
  }
  vpc_id = "vpc-12345678"

  desync_mitigation_mode = "defensive"
}

module "alb" {
  source  = "pcidssv321.compliance.tf/terraform-aws-modules/alb/aws"
  version = ">=10.0.0,<11.0.0"

  access_logs = {
    bucket  = "example-bucket-abc123"
    enabled = true
  }
  internal = true
  listeners = {
    https = {
      certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
      forward = {
        target_group_key = "default"
      }
      protocol   = "HTTPS"
      ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
    }
  }
  load_balancer_type = "application"
  name               = "abc123"
  security_groups    = ["sg-abc12345"]
  subnets            = ["subnet-abc123", "subnet-def456"]
  target_groups = {
    default = {
      create_attachment = false
      name_prefix       = "def-"
      port              = 443
      protocol          = "HTTPS"
      target_type       = "ip"
    }
  }
  vpc_id = "vpc-12345678"

  desync_mitigation_mode = "defensive"
}

If you use terraform-aws-modules/alb/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 "alb" {
  source  = "terraform-aws-modules/alb/aws"
  version = ">=10.0.0,<11.0.0"

  access_logs = {
    bucket  = "example-bucket-abc123"
    enabled = true
  }
  internal = true
  listeners = {
    https = {
      certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
      forward = {
        target_group_key = "default"
      }
      protocol   = "HTTPS"
      ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
    }
  }
  load_balancer_type = "application"
  name               = "abc123"
  security_groups    = ["sg-abc12345"]
  subnets            = ["subnet-abc123", "subnet-def456"]
  target_groups = {
    default = {
      create_attachment = false
      name_prefix       = "def-"
      port              = 443
      protocol          = "HTTPS"
      target_type       = "ip"
    }
  }
  vpc_id = "vpc-12345678"

  desync_mitigation_mode = "defensive"
}

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

resource "aws_lb" "this" {
  access_logs {
    bucket = "pofix-logs-abc123"
  }
  internal = true
  name     = "pofix-abc123"
  subnets  = ["subnet-abc123", "subnet-def456"]

  desync_mitigation_mode = "defensive"
}

What this control checks

In the aws_lb resource with load_balancer_type = "application", the desync_mitigation_mode argument controls this behavior. Accepted values are "monitor", "defensive", and "strictest". The Terraform default is "defensive", which passes this control. A configuration explicitly set to "monitor" fails. To pass, either omit desync_mitigation_mode (taking the "defensive" default) or set it to "defensive" or "strictest". No other resources or arguments are involved.

Common pitfalls

  • Default is compliant but explicit overrides are common

    The Terraform default for desync_mitigation_mode on aws_lb is "defensive", so new ALBs pass without any explicit setting. The risk is older module code or configurations left over from a debugging session that set it to "monitor" and never got reverted. That override silently persists. Search your codebase for desync_mitigation_mode before assuming you're clean.

  • Strictest mode can break chunked transfer encoding edge cases

    "strictest" rejects any request with ambiguous headers, including some technically valid chunked-encoding patterns. Get this wrong on an ALB fronting file uploads or streaming payloads and you'll see 400 errors for legitimate traffic. Validate behavior at "defensive" first, confirm DesyncMitigationMode_NonCompliant_Request_Count stays low, then decide whether the extra restriction is worth it.

  • Control applies only to ALBs, not NLBs or GLBs

    desync_mitigation_mode is only valid on aws_lb resources with load_balancer_type = "application". Set it on a Network or Gateway Load Balancer and Terraform will error. If your modules iterate over multiple load balancer types, gate this attribute behind a conditional.

Audit evidence

AWS Config's alb-desync-mode-check managed rule provides evaluation results showing ALB compliance status across the account. Console evidence comes from EC2 > Load Balancers: select each ALB and check the "Desync mitigation mode" attribute on the Attributes tab for "Defensive" or "Strictest".

The DesyncMitigationMode_NonCompliant_Request_Count CloudWatch metric per ALB supplements evidence by showing whether suspect traffic is actually reaching the load balancer. Security Hub aggregates this control's finding status across accounts and regions into a single consolidated artifact.

Framework-specific interpretation

NIST Cybersecurity Framework v1.1: PR.PT under the Protect function covers protective technology for communications and control networks. Desync mitigation normalizes or rejects malformed HTTP before it reaches back-end services, which is exactly the kind of traffic hardening PR.PT calls for.

PCI DSS v3.2.1: Requirements 6.5 and 6.6 call for protection against web-facing application attacks, including injection and input validation failures. Desync mitigation is a complementary technical control that reduces exposure to malformed HTTP techniques, but it doesn't replace secure coding practices, code review, or WAF requirements.

Tool mappings

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

  • Compliance.tf Control: elb_application_lb_desync_mitigation_mode

  • AWS Config Managed Rule: ALB_DESYNC_MODE_CHECK

  • Checkov Check: CKV_AWS_328

  • Powerpipe Control: aws_compliance.control.elb_application_lb_desync_mitigation_mode

  • Prowler Check: elbv2_desync_mitigation_mode

  • AWS Security Hub Control: ELB.12

Last reviewed: 2026-03-09