file: enforce auth realms on plugin-dispatched URL prefixes - #35
Open
JuliusBairaktaris wants to merge 1 commit into
Open
file: enforce auth realms on plugin-dispatched URL prefixes#35JuliusBairaktaris wants to merge 1 commit into
JuliusBairaktaris wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Fixes a bypass where requests dispatched via .check_url handlers skip uh_auth_check() entirely, causing configured HTTP auth realms to not be enforced on ubus/lua/ucode prefixes.
Changes:
- Added
uh_dispatch_auth_check()to evaluate the auth realm for.check_urldispatches using the URL path without the query string. - Updated
uh_handle_request()to run the auth check before invoking a matched plugin handler.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+973
to
+985
| char path[PATH_MAX]; | ||
| const char *auth, *q; | ||
| char *user, *pass; | ||
| size_t len; | ||
|
|
||
| q = strchr(url, '?'); | ||
| len = q ? (size_t)(q - url) : strlen(url); | ||
|
|
||
| if (len >= sizeof(path)) | ||
| len = sizeof(path) - 1; | ||
|
|
||
| memcpy(path, url, len); | ||
| path[len] = 0; |
| memcpy(path, url, len); | ||
| path[len] = 0; | ||
|
|
||
| blobmsg_parse(hdr_policy, 1, tb, blob_data(cl->hdr.head), blob_len(cl->hdr.head)); |
uh_auth_check() is reached only from __handle_file_request(). uh_handle_request() consults dispatch_find(url, NULL) first and returns early when a handler matches, so requests routed to a .check_url handler never pass an auth check: ubus ubus.c uh_ubus_check_url() conf.ubus_prefix lua lua.c check_lua_url() conf.lua_prefix ucode ucode.c check_ucode_url() conf.ucode_prefix CGI registers .check_path instead and is matched from inside __handle_file_request(), after the auth check, which is why CGI-served paths are unaffected and the gap is easy to miss. An operator configuring a `config httpauth` section (uhttpd.init writes it to the realm file consumed by uh_auth_check) for a path served by one of those handlers receives no authentication on that path, with no warning. Evaluate the realm before dispatching, on the very URL dispatch_find() matched and uh_invoke_handler() is about to receive, so the auth check and the plugin matcher cannot disagree about what is covered. The query string needs no removal: uh_auth_check() selects a realm by comparing its leading strlen(realm->path) bytes, and a query can only follow the path, so it can never turn a matching realm into a non-matching one. Assisted-by: Claude:claude-opus-5 Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
JuliusBairaktaris
force-pushed
the
auth-plugin-prefixes
branch
from
August 1, 2026 09:37
a9035da to
befbd20
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
uh_auth_check()is reached only from__handle_file_request().uh_handle_request()consultsdispatch_find(url, NULL)first and returns early when a handler matches, so requests routed to a.check_urlhandler never pass an auth check:ubus.cuh_ubus_check_url()conf.ubus_prefixlua.ccheck_lua_url()conf.lua_prefixucode.ccheck_ucode_url()conf.ucode_prefixCGI registers
.check_pathinstead and is matched from inside__handle_file_request(), after the auth check, which is why CGI-served paths are unaffected and the gap is easy to miss.An operator configuring a
config httpauthsection —uhttpd.initcreate_httpauth()writes it to the realm file consumed byuh_auth_check()— for a path served by one of those handlers receives no authentication on that path, with no warning or error.This patch evaluates the realm before dispatching, against the URL path with the query string removed. Realm matching is a prefix compare in URL space, and the plugin matchers use
uh_path_match()on the same unmodified URL, so the two agree on what is covered.Testing
Compiles clean under the package's own strict flags (
-Os -Wall -Werror -Wmissing-declarations --std=gnu99, aarch64 cortex-a53 musl, gcc 15.3.0).I want to be straight about the limits: this is compile-verified and derived from reading the dispatch path — I have not stood up a uhttpd with an httpauth realm on a ubus prefix and observed the 401 appear. If you'd like that before merging, say so and I'll produce it.
Note
__handle_file_request()has a second unauthenticated dispatch in the error-handler branch:I left it alone — it is reachable only through
conf.error_handler, which is administrator-configured rather than attacker-chosen, so it is a much weaker path. It is the same shape as the bug being fixed though, so if you'd prefer both handled here I'm happy to extend the patch.