Skip to content

3.1.7 version introduces a BC break in host validation #3141

@helvete

Description

@helvete

A feature to validate host http header no matter what introduces backwards compatibility break.

The bug presents itself by regarding the host invalid (false-positive)

A host like 069ef83c8f81497b8e26015bea0db3b5._robot-interface.roboton-cloud-pre-release:33129 is treated as invalid which in turn regards the request invalid and the request is subsequently terminated with 400 Bad request (in Flask application using Werkzeug 3.1.7)

Expected behaviour would be not to unnecessarily validate the host or to validate the host in a way that passes for valid hosts

Environment:

  • Python version: 3.11.15
  • Werkzeug version: 3.1.7

A workaround we are using currently is to stick with Werkzeug version 3.1.6.

The bug introduced itself in the environment of AWS while using Service discovery (SRV domain records) which are then (within the internal network) translated into hosts that look like this: 069ef83c8f81497b8e26015bea0db3b5._robot-interface.roboton-cloud-pre-release:33129

Here you are a snippet to reproduce the bug (logic to replicate based on code introduced in this PR):

#!/usr/local/bin/python                                                         
import re                                                                       
                                                                                
_host_re = re.compile(                                                          
    r"""                                                                        
    (                                                                           
        [a-z0-9.-]+  # domain or ipv4                                           
    |                                                                           
        \[[a-f0-9]*:[a-f0-9.:]+]  # ipv6                                        
    )                                                                           
    (?::[0-9]+)?  # optional port                                               
    """,                                                                        
    flags=re.ASCII | re.IGNORECASE | re.VERBOSE,                                
)                                                                               
                                                                                
hostname = '069ef83c8f81497b8e26015bea0db3b5._robot-interface.roboton-cloud-pre-release:33129'
                                                                                
result = True                                                                   
if _host_re.fullmatch(hostname) is None:                                        
    result = False                                                              
                                                                                
print(result)

This should return True

Also wget example describing how plain request looks like:

$ wget -S --debug -q -O- --content-on-error 8b737aebe7804c938d525be06c8e4128._robot-interface.roboton-cloud-staging:32861/ri/enum/field-procedure
Setting --quiet (quiet) to 1                                                    
Setting --output-document (outputdocument) to -                                 
Setting --content-on-error (contentonerror) to 1                                
DEBUG output created by Wget 1.14 on linux-gnu.                                 
                                                                                
URI encoding = ‘UTF-8’                                                          
Converted file name 'field-procedure' (UTF-8) -> 'field-procedure' (UTF-8)      
Caching 8b737aebe7804c938d525be06c8e4128._robot-interface.roboton-cloud-staging => 10.0.1.67
Created socket 3.                                                               
Releasing 0x0000000001c54100 (new refcount 1).                                  
                                                                                
---request begin---                                                             
GET /ri/enum/field-procedure HTTP/1.1                                           
User-Agent: Wget/1.14 (linux-gnu)                                               
Accept: */*                                                                     
Host: 8b737aebe7804c938d525be06c8e4128._robot-interface.roboton-cloud-staging:32861
Connection: Keep-Alive                                                          
                                                                                
---request end---                                                               
                                                                                
---response begin---                                                            
HTTP/1.1 400 BAD REQUEST                                                        
Server: gunicorn                                                                
Date: Tue, 24 Mar 2026 14:27:50 GMT                                             
Connection: close                                                               
Content-Type: application/json                                                  
Content-Length: 47                                                              
Vary: Accept-Encoding                                                           
                                                                                
---response end---                                                              
  HTTP/1.1 400 BAD REQUEST                                                      
  Server: gunicorn                                                              
  Date: Tue, 24 Mar 2026 14:27:50 GMT                                           
  Connection: close                                                             
  Content-Type: application/json                                                
  Content-Length: 47                                                            
  Vary: Accept-Encoding                                                         
{                                                                               
  "detail": {},                                                                 
  "message": "Bad Request"                                                      
}                                                                               
Closed fd 3

Don't hesitate to ask for further details. Thanks in advance

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions