-
Notifications
You must be signed in to change notification settings - Fork 232
Description
I've got an authentication service set up that will return with a 401 response unless an appropriate Authorization header is provided.
If that authorization service does not provide a WWW-Authenticate header, the nginx worker process can segfault if more_set_headers is used to add the WWW-Authenticate header.
A lot of my config comes from using global-auth-url in the ingress-nginx controller, but this reproduces with just an OpenResty install.
Relevant nginx.conf
http {
worker_processes 1;
...
upstream upstream_balancer {
server 0.0.0.1;
keepalive 320;
keepalive_time 1h;
keepalive_timeout 60s;
keepalive_requests 10000;
}
more_set_headers -s "401" 'WWW-Authenticate: Bearer realm="https://my.org/auth"';
server {
...
listen: 55555;
server_name localhost;
location /_external-auth-Lw-Prefix {
internal;
access_log off;
set $proxy_upstream_name "default-auth";
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Forwarded-Proto "";
proxy_method GET;
proxy_set_header Host unix;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Sent-From "default-copy";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Auth-Request-Redirect $request_uri;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_request_buffering on;
proxy_ssl_server_name on;
proxy_pass_request_headers on;
client_max_body_size 1m;
proxy_http_version 1.1;
set $target "http://127.0.0.1:8081/";
proxy_pass $target;
}
location / {
port_in_redirect off;
set $balancer_ewma_score -1;
set $proxy_upstream_name "default-auth";
set $proxy_host $proxy_upstream_name;
set $pass_access_scheme $scheme;
set $pass_server_port $server_port;
set $best_http_host $http_host;
set $pass_port $pass_server_port;
set $proxy_alternative_upstream_name "";
auth_request /_external-auth-Lw-Prefix;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
auth_request_set $authHeader0 $upstream_http_;
proxy_set_header '' $authHeader0;
client_max_body_size 1m;
proxy_set_header Host $best_http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Forwarded-Scheme $pass_access_scheme;
proxy_set_header X-Scheme $pass_access_scheme;
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
proxy_set_header Proxy "";
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_max_temp_file_size 1024m;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_cookie_domain off;
proxy_cookie_path off;
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 0;
proxy_next_upstream_tries 3;
proxy_pass http://upstream_balancer;
proxy_redirect off;
}
And a simple web site sitting on 8081 that responds with:
- Status 401, no WWW-Authenticate header if
X-Skip-Header: 1header is provided on the request - Status 401, WWW-Authenticate header provided otherwise
$ curl -v http://localhost:55555/ --http1.1
* Host localhost:55555 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:55555...
* connect to ::1 port 55555 from ::1 port 40470 failed: Connection refused
* Trying 127.0.0.1:55555...
* Connected to localhost (127.0.0.1) port 55555
> GET / HTTP/1.1
> Host: localhost:55555
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< Server: openresty/1.27.1.2
< Date: Tue, 17 Jun 2025 18:57:45 GMT
< Content-Type: text/html
< Content-Length: 185
< Connection: keep-alive
< WWW-Authenticate: Bearer realm="https://my.org/auth"
<
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>openresty/1.27.1.2</center>
</body>
</html>
* Connection #0 to host localhost left intactworks successfully. However,
$ curl -v http://localhost:55555/ --http1.1 -H "X-Skip-Header: 1"
* Host localhost:55555 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:55555...
* connect to ::1 port 55555 from ::1 port 40116 failed: Connection refused
* Trying 127.0.0.1:55555...
* Connected to localhost (127.0.0.1) port 55555
> GET / HTTP/1.1
> Host: localhost:55555
> User-Agent: curl/8.5.0
> Accept: */*
> X-Skip-Header: 1
>
* Empty reply from server
* Closing connection
curl: (52) Empty reply from servercan sometimes occur. This seems to happen more frequently if https is used, and for non-https requests I've had success throwing lots of traffic at the server with bombardier until the server starts having issues. When this happens, I see entries like the following in the nginx error log:
2025/06/17 14:05:26 [alert] 3423044#3423044: worker process 3426331 exited on signal 11 (core dumped)
Once in this state, any request with X-Skip-Headers: 1 will terminate abruptly; whereas other requests will succeed as expected.
I'm thinking this might be related to this nginx change: https://trac.nginx.org/nginx/ticket/485.