Skip to content

bug: loader input handling — NewFromDisk mangles special-char paths, nil HTTP options panics, InferLoader base64-corrupts scripts #163

Description

@robbyt

Three independent input-handling defects in platform/script/loader/, grouped by package. Each has a distinct fix.

1. NewFromDisk mangles or rejects paths containing #, %, or ?

platform/script/loader/fromDisk.go:45-57 round-trips the filesystem path through url.Parse, and GetReader (:94-96) opens l.sourceURL.Path. # becomes a fragment delimiter, % percent-escaping, ? a query — none valid in a filename.

Repro (confirmed):

  • /dir/file#1.risorsourceURL.Path becomes /dir/file; GetReaderopen /dir/file: no such file or directory.
  • /dir/100%zz.risorNewFromDisk fails: invalid URL escape "%zz".
  • a%20b.risor → silently decoded to a b.risor.

Fix: store the cleaned path and open it directly (os.Open(l.path)). If a *url.URL is needed for GetSourceURL, build it as &url.URL{Scheme: "file", Path: path}; never derive the open path from a parsed URL.

2. NewFromHTTPWithOptions(url, nil) panics

platform/script/loader/fromHTTP.go:195 dereferences options (options.Timeout, options.InsecureSkipVerify, options.TLSConfig) with no nil check. A caller passing nil (a reasonable "use defaults") crashes instead of getting defaults or an error.

Repro (confirmed): invalid memory address or nil pointer dereference.

Fix: if options == nil { options = DefaultHTTPOptions() } at the top of the function.

3. InferLoader silently base64-decodes plain scripts that parse as base64

platform/script/loader/inference.go:80-83 passes the remaining string to NewFromStringBase64 (fromString.go:43-58), which decodes whenever the input parses as base64, with no signal that it was actually encoded. Any script whose trimmed text is coincidentally valid base64 (length a multiple of 4, base64 alphabet) is corrupted into binary.

Repro (confirmed): InferLoader("true") returns a loader whose content is the 3 bytes \xb6\xbb\x9e instead of the script text true.

Fix: default the string fallback to NewFromString; attempt base64 only behind an explicit opt-in or a stricter heuristic. At minimum, document that InferLoader is lossy for base64-shaped scripts.

Impact

Medium — each turns a reasonable input into a crash, a silent corruption, or an unexpected error. All confirmed by repro; none covered by existing tests.

Fix

Address each as above and add regression tests: a filename containing #/%/?, NewFromHTTPWithOptions(url, nil), and InferLoader on a base64-shaped plain script.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions