mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-05 06:08:59 +00:00
fix: reject absolute urls in the content resolver, register the mutants
Review CODE-REVIEW-225-r1. M1: urlsplit(url).path was trusted even when the url carried a scheme or an authority, so "https://evil.example/houseplan_files/files/m1/doc.pdf" resolved onto a local file while _looks_internal kept calling it external — the mirror image of the inconsistency this resolver exists to prevent. Only a same-document reference is resolved by its path now. M2: the three mutants the spec described are registered in scripts/mutation-gate.mjs instead of living as a one-off manual run. The traversal entry drops both structural checks at once on purpose: taken one at a time the defence is layered (sanitize_marker_id turns ".." into "misc") and the mutant would be equivalent — established by running it. Issue: #225 User-Visible: no
This commit is contained in:
@@ -357,7 +357,16 @@ def _internal_path(root: Path, url: str) -> tuple[str, Path] | None:
|
||||
# every backup holding one refused to import (issue #225). Path segments
|
||||
# keep doing the guarding: dropping the query cannot widen what a segment
|
||||
# is allowed to be.
|
||||
url = urlsplit(url).path
|
||||
#
|
||||
# Only a same-document reference may be trusted this way: with a scheme or
|
||||
# an authority the path belongs to another host, and taking it would let
|
||||
# "https://evil.example/houseplan_files/files/m1/doc.pdf" resolve onto a
|
||||
# local file (review CODE-REVIEW-225-r1, M1). Such a url stays external,
|
||||
# which is also what _looks_internal says about it.
|
||||
parsed = urlsplit(url)
|
||||
if parsed.scheme or parsed.netloc:
|
||||
return None
|
||||
url = parsed.path
|
||||
content_plan = CONTENT_URL + "/plans/_/"
|
||||
if url.startswith(content_plan) or url.startswith(PLANS_URL + "/"):
|
||||
prefix = content_plan if url.startswith(content_plan) else PLANS_URL + "/"
|
||||
|
||||
Reference in New Issue
Block a user