Commit a3e53f3
security: fix auth bypass via path-normalization mismatch (dot-segments)
The v2.0 auth pipeline interpreted the request path two different ways
that disagreed on ".." handling, letting an attacker reach a protected
handler with authentication skipped.
should_skip_auth() ran the path through normalize_path(), which collapses
"." / ".." segments, then matched it against auth_skip_paths. But the
route matcher (radix_tree::find via mr->standardized_url) and the regex
tier saw the raw path -- standardize_url() only collapses duplicate '/'
and a trailing '/', never dot-segments. On a failed descent the radix
walk falls back to the deepest matched prefix terminus.
So with a global auth_handler, a protected register_prefix("/admin") (or
"/admin/.*" regex) route, and auth_skip_paths({"/public/*"}):
GET /admin/../public/x
normalized to "/public/x" for the auth-skip check (auth skipped) yet
still routed to the protected "/admin" prefix handler -- served
unauthenticated. (Requires a client that does not pre-normalize "..",
e.g. curl --path-as-is; MHD does not collapse dot-segments.)
Fix: canonicalize once, at the single point in answer_to_connection where
the routing/auth path is derived, by applying normalize_path() to the
standardized URL. The router, should_skip_auth(), and the route-cache key
now all interpret the path identically; the request above is uniformly
treated as "/public/x" and never reaches /admin. The extra normalize_path
in should_skip_auth() is now idempotent.
Adds an end-to-end regression test (auth_skip_dotdot_no_route_confusion)
that sends "/admin/../public/x" with CURLOPT_PATH_AS_IS and asserts the
protected handler is never reached; it fails on the pre-fix code with
ADMIN_SECRET != PUBLIC_OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NpysYDDJac63yz2mZKKiDf1 parent 7ee0463 commit a3e53f3
2 files changed
Lines changed: 79 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
417 | 417 | | |
418 | 418 | | |
419 | 419 | | |
420 | | - | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
421 | 434 | | |
422 | 435 | | |
423 | 436 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
972 | 972 | | |
973 | 973 | | |
974 | 974 | | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
| 1014 | + | |
| 1015 | + | |
| 1016 | + | |
| 1017 | + | |
| 1018 | + | |
| 1019 | + | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
975 | 1040 | | |
976 | 1041 | | |
977 | 1042 | | |
| |||
0 commit comments