Preventing directory traversal in nginx ingress in Kubernetes

I have the following ingress defined:

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: someName
  namespace: test
  annotations:
    kubernetes.io/ingress.class: "ingress-public"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "JSESSIONID"
    nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"
    nginx.ingress.kubernetes.io/server-snippet: |
      # block if not / or /test or /something
      if ($request_uri !~* "(^\/(?:(?:test|something)(?:\/|$)|$))") {
        return 404 ;
        break;
      }
      # redirect if proto_http
      if ($http_x_forwarded_proto = 'http') {
        return 301 https://$host$request_uri;
        break;
      }

      # hsts required header
      add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

spec:
  rules:
  - host: myhost.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: someservice
          servicePort: 80

The regex covers most cases where requests are something like /config - as this doesn't match the regex, it returns a 404.

There are two problems that I currently have.

  1. Requesting /test%2F..%2Fconfig does NOT return a 404 even though this doesn't match the regex.
  2. Requesting /test/..%2Fconfig allows you to reach /config.

So is there either a better regex that would cover these cases, or is there a way to convert $request_uri into an absolute uri so the regex can work on that instead of an encoded uri?

The regex is here with some test cases: https://regex101.com/r/Msu402/1


You might want to try using a location (doc) or $uri (doc) since both match a normalized URI. Since if is evil I would suggest a location (untested):

location ~* ^/(?!test|something) {
  return 404;
}

Edit: I reread your question and it should BLOCK access to the mentioned locations in the regex. So I added the "not"...