fix(javascript): keep directory-form HTML URL references distinct from files (#4646)

* fix(javascript): keep directory-form HTML URL references distinct from files

Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>

* test(javascript): cover directory-form HTML URL references

Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>

---------

Signed-off-by: Vinícius DS Andrade <95101505+viniciusdsandrade@users.noreply.github.com>
This commit is contained in:
Vinícius Andrade authored and GitHub committed 2026-10-23 02:28:05 +08:00
1 parent db8556e724
commit 75575f2006
3 files changed
+56 -24

No files matched your search

@@ -1315,11 +1315,19 @@ const htmlCandidate = (
"The HTML reference path percent-decodes to NUL or to bytes that are not UTF-8.",
]);
if (declaredPath.startsWith("/"))
return urlRelativeCandidate("", declaredPath);
return exactUrlPathCandidate(
declaredPath,
urlRelativeCandidate("", declaredPath),
"HTML",
);
if (base === undefined || base === null || base === "")
return declaredPath === ""
? input.sourcePath
: urlRelativeCandidate(posix.dirname(input.sourcePath), declaredPath);
: exactUrlPathCandidate(
declaredPath,
urlRelativeCandidate(posix.dirname(input.sourcePath), declaredPath),
"HTML",
);
// A local base href is a second untrusted path input; apply the same
// admission rules a declared path gets so it cannot smuggle traversal or
// separator syntax past canonicalization.
@@ -1338,23 +1346,28 @@ const htmlCandidate = (
urlDirectoryState(posix.dirname(input.sourcePath)),
decodedBase,
);
if (declaredPath === "") {
const basePath = urlPathCandidate(baseState);
return typeof basePath === "string"
? exactUrlPathCandidate(decodedBase, basePath, "HTML")
: basePath;
}
return urlPathCandidate(
applyUrlReference(urlBaseDirectory(baseState), declaredPath),
if (declaredPath === "")
return exactUrlPathCandidate(
decodedBase,
urlPathCandidate(baseState),
"HTML",
);
return exactUrlPathCandidate(
declaredPath,
urlPathCandidate(
applyUrlReference(urlBaseDirectory(baseState), declaredPath),
),
"HTML",
);
};
const exactUrlPathCandidate = (
declared: string,
candidate: string,
candidate: string | CandidateResolution,
kind: "HTML" | "URL" | "module URL",
): string | CandidateResolution => {
if (!urlPathIsDirectory(declared)) return candidate;
if (typeof candidate !== "string" || !urlPathIsDirectory(declared))
return candidate;
const confined = confineCandidate(candidate);
if (typeof confined !== "string") return confined;
return unresolvedCandidate("not-found", [