From f1959ae9621af4473f7daa831d5318efdaccd97f Mon Sep 17 00:00:00 2001 From: tiymat <138939221+tiymat@users.noreply.github.com> Date: Wed, 27 May 2026 00:44:31 -0230 Subject: [PATCH] urlapi: fix an issue parsing file URLs Fixes #21743 Closes #21764 --- lib/urlapi.c | 8 +++++++- tests/libtest/lib1560.c | 6 +++++- tests/unit/unit1675.c | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/urlapi.c b/lib/urlapi.c index 589a400834..a5ec95032b 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -876,13 +876,19 @@ UNITTEST CURLUcode parse_file(const char *url, size_t urllen, CURLU *u, path = &url[5]; pathlen = urllen - 5; + /* RFC 8089: file-hier-part = ( "//" auth-path ) / local-path, where + local-path also starts with a "/". So reject anything that doesn't + start with at least one "/" */ + if(path[0] != '/') + return CURLUE_BAD_FILE_URL; + /* Extra handling URLs with an authority component (i.e. that start with * "file://") * * We allow omitted hostname (e.g. file:/) -- valid according to * RFC 8089, but not the (current) WHAT-WG URL spec. */ - if(path[0] == '/' && path[1] == '/') { + if(path[1] == '/') { /* swallow the two slashes */ const char *ptr = &path[2]; diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c index cd2cbec589..bdf8b56cad 100644 --- a/tests/libtest/lib1560.c +++ b/tests/libtest/lib1560.c @@ -886,7 +886,11 @@ static const struct urltestcase get_url_list[] = { {"file:///.", "file:///", 0, 0, CURLUE_OK}, {"file:///./", "file:///", 0, 0, CURLUE_OK}, {"file:///a", "file:///a", 0, 0, CURLUE_OK}, - {"file:./", "file://", 0, 0, CURLUE_OK}, + {"file:./", "", 0, 0, CURLUE_BAD_FILE_URL}, + {"file:foo", "", 0, 0, CURLUE_BAD_FILE_URL}, + {"file:foo/bar", "", 0, 0, CURLUE_BAD_FILE_URL}, + {"file:?q", "", 0, 0, CURLUE_BAD_FILE_URL}, + {"file:#f", "", 0, 0, CURLUE_BAD_FILE_URL}, {"http://example.com/hello/../here", "http://example.com/hello/../here", CURLU_PATH_AS_IS, 0, CURLUE_OK}, diff --git a/tests/unit/unit1675.c b/tests/unit/unit1675.c index 024c7ff400..b5b372336a 100644 --- a/tests/unit/unit1675.c +++ b/tests/unit/unit1675.c @@ -267,6 +267,10 @@ static CURLcode test_unit1675(const char *arg) {"file:///etc/hosts", "/etc/hosts", TRUE}, {"file://localhost/etc/hosts", "/etc/hosts", TRUE}, {"file://apple/etc/hosts", "/etc/hosts", FALSE}, + {"file:foo", NULL, FALSE}, + {"file:./", NULL, FALSE}, + {"file:?q", NULL, FALSE}, + {"file:#f", NULL, FALSE}, #ifdef _WIN32 {"file:///c:/windows/system32", "c:/windows/system32", TRUE}, {"file://localhost/c:/windows/system32", "c:/windows/system32", TRUE},