Skip to content

Harden open-file: protocol allowlist + safe spawn for URLs#72

Merged
liftaris merged 2 commits into
devfrom
task/t_3a5c3ad2-harden-open-file
May 21, 2026
Merged

Harden open-file: protocol allowlist + safe spawn for URLs#72
liftaris merged 2 commits into
devfrom
task/t_3a5c3ad2-harden-open-file

Conversation

@liftaris
Copy link
Copy Markdown
Owner

What

Splits src/utils/open-file.ts into two entry points:

  • openFile(path) — local file paths via the open package. Unchanged; all existing consumers (FileLink, ChafaImage, MediaChip, profile dialog) keep using it.
  • openUrl(raw) — new. External URLs only. Parses via new URL() and rejects anything whose protocol is not http:/https:, so a model-emitted file:///, data:, or javascript: URL can never reach a local handler. Spawns the platform opener with an argv array (no shell), so metacharacters in query strings cannot be interpreted as commands. open on darwin, explorer.exe on win32 (not cmd /c start), xdg-open on Linux/BSDs, no-op elsewhere. A no-op error listener is attached before unref() so ENOENT from a missing opener doesn't crash the TUI.

Why now

This is the sink for the upcoming clickable-URL tokenizer in chat messages. openUrl has no consumers yet in this PR — the tokenizer lands separately and depends on this being merged first.

Tests

test/open-file.test.ts — 19 cases: protocol allowlist (accepted + every rejected scheme), per-platform argv dispatch with spawn mocked, sync-throw and async-ENOENT error paths, hostname edge cases.

tsc clean, 1001/1001 pass.

liftaris added 2 commits May 20, 2026 12:11
Split openFile into two exports: openFile (local paths, unchanged) and
openUrl (external URLs, http(s)-only, spawned with no shell).

openUrl parses via new URL() and rejects anything non-http(s) so a
model-emitted file:///, data:, or javascript: URL can never reach a
local handler. URLs are forwarded via child_process.spawn with an argv
array, so shell metacharacters (; & ` $ | < >) in query strings cannot
be interpreted as commands. Platform openers: open on darwin,
explorer.exe on win32 (not cmd /c start), xdg-open on Linux/BSDs,
no-op everywhere else.

A no-op 'error' listener is attached before unref() so ENOENT from a
missing xdg-open doesn't crash the TUI as an unhandled EventEmitter
event.
@liftaris liftaris merged commit 8782b48 into dev May 21, 2026
1 check passed
@liftaris liftaris mentioned this pull request May 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.7.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@liftaris liftaris deleted the task/t_3a5c3ad2-harden-open-file branch May 22, 2026 08:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant