internal/proxy/request.go, forward and rewrite: httputil.ReverseProxy writes the path the app receives from URL.EscapedPath(). When the path as the client sent it holds a character Go's net/url escapes, such as |, ^, {, }, \ or a byte above 127, EscapedPath does not return that path. It decodes the whole path and escapes it again, so an encoded slash (%2F) reaches the app as /.
Repro, at the defaults, each request sent as written on a raw connection:
GET /a%2Fb|c HTTP/1.1: the app receives /a/b%7Cc.
GET /feat%2Fx/file^1 HTTP/1.1: the app receives /feat/x/file%5E1.
GET /x%2Fy/café HTTP/1.1, its UTF-8 bytes unescaped: the app receives /x/y/caf%C3%A9.
A test in internal/proxy that compares the app's r.RequestURI with the target sent fails on all three. Browsers send | and ^ in a path unescaped.
README, "What it does so far": "Passes each request to the app and the app's answer back unchanged: method, path, query, headers, body and status." An encoded slash turned into a slash can route the request to another resource in the app.
It also breaks what pathExempt relies on since #77, that the path as sent is the path the app receives. With SWWAF_RATE_LIMIT_EXEMPT_PATHS=/assets/, /assets/x%2Fy|z is exempt (a test of pathExempt shows it), though the README says a request "whose path as sent holds an encoded slash (%2F or %2f), is never exempt". The app receives /assets/x/y%7Cz there, so the exemption fits what the app gets, and the README's description does not.
Severity: minor. It needs an encoded reserved character and a character Go escapes in the same path, and it lets through or refuses nothing it should not.
Model: opus-5-5
`internal/proxy/request.go`, `forward` and `rewrite`: `httputil.ReverseProxy` writes the path the app receives from `URL.EscapedPath()`. When the path as the client sent it holds a character Go's `net/url` escapes, such as `|`, `^`, `{`, `}`, `\` or a byte above 127, `EscapedPath` does not return that path. It decodes the whole path and escapes it again, so an encoded slash (`%2F`) reaches the app as `/`.
Repro, at the defaults, each request sent as written on a raw connection:
- `GET /a%2Fb|c HTTP/1.1`: the app receives `/a/b%7Cc`.
- `GET /feat%2Fx/file^1 HTTP/1.1`: the app receives `/feat/x/file%5E1`.
- `GET /x%2Fy/café HTTP/1.1`, its UTF-8 bytes unescaped: the app receives `/x/y/caf%C3%A9`.
A test in `internal/proxy` that compares the app's `r.RequestURI` with the target sent fails on all three. Browsers send `|` and `^` in a path unescaped.
README, "What it does so far": "Passes each request to the app and the app's answer back unchanged: method, path, query, headers, body and status." An encoded slash turned into a slash can route the request to another resource in the app.
It also breaks what `pathExempt` relies on since https://git.eeqj.de/sneak/smallwebwaf/issues/77, that the path as sent is the path the app receives. With `SWWAF_RATE_LIMIT_EXEMPT_PATHS=/assets/`, `/assets/x%2Fy|z` is exempt (a test of `pathExempt` shows it), though the README says a request "whose path as sent holds an encoded slash (`%2F` or `%2f`), is never exempt". The app receives `/assets/x/y%7Cz` there, so the exemption fits what the app gets, and the README's description does not.
Severity: minor. It needs an encoded reserved character and a character Go escapes in the same path, and it lets through or refuses nothing it should not.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
internal/proxy/request.go,forwardandrewrite:httputil.ReverseProxywrites the path the app receives fromURL.EscapedPath(). When the path as the client sent it holds a character Go'snet/urlescapes, such as|,^,{,},\or a byte above 127,EscapedPathdoes not return that path. It decodes the whole path and escapes it again, so an encoded slash (%2F) reaches the app as/.Repro, at the defaults, each request sent as written on a raw connection:
GET /a%2Fb|c HTTP/1.1: the app receives/a/b%7Cc.GET /feat%2Fx/file^1 HTTP/1.1: the app receives/feat/x/file%5E1.GET /x%2Fy/café HTTP/1.1, its UTF-8 bytes unescaped: the app receives/x/y/caf%C3%A9.A test in
internal/proxythat compares the app'sr.RequestURIwith the target sent fails on all three. Browsers send|and^in a path unescaped.README, "What it does so far": "Passes each request to the app and the app's answer back unchanged: method, path, query, headers, body and status." An encoded slash turned into a slash can route the request to another resource in the app.
It also breaks what
pathExemptrelies on since #77, that the path as sent is the path the app receives. WithSWWAF_RATE_LIMIT_EXEMPT_PATHS=/assets/,/assets/x%2Fy|zis exempt (a test ofpathExemptshows it), though the README says a request "whose path as sent holds an encoded slash (%2For%2f), is never exempt". The app receives/assets/x/y%7Czthere, so the exemption fits what the app gets, and the README's description does not.Severity: minor. It needs an encoded reserved character and a character Go escapes in the same path, and it lets through or refuses nothing it should not.
Model: opus-5-5