Skip to content

security: confine file commands and validate deep-link targets#57

Merged
sam-powers merged 1 commit into
mainfrom
security/confine-file-commands
Jun 13, 2026
Merged

security: confine file commands and validate deep-link targets#57
sam-powers merged 1 commit into
mainfrom
security/confine-file-commands

Conversation

@sam-powers

Copy link
Copy Markdown
Owner

What

Hardens the Tauri file-IO boundary, the most attacker-exposed surface in the app.

read_file / write_file / delete_file were unconstrained filesystem primitives. They're reachable from the frontend and — through the quill://open?file=… deep link, which any web page can fire — indirectly from a hostile origin. A crafted path could read /etc/passwd or overwrite an arbitrary file.

Changes

  • ensure_allowed_path confines the three commands to Markdown documents and their .comments.json sidecars — the only paths any legitimate caller ever uses. The native open/save dialogs already restrict the user to .md, so no real capability is lost.
  • parse_quill_open now resolves the decoded path and accepts it only if it canonicalizes to an existing regular .md/.markdown file (symlink target re-checked). A hostile quill://open?file=/etc/passwd can no longer reach read_file at all.

Tests

Five new unit tests (35 Rust tests total, all green): path policy accept/reject, the confined commands refusing disallowed paths, and deep-link validation across existing file / missing file / non-Markdown target / directory-with-.md-suffix / wrong host.

Full local bar green: cargo fmt --check, cargo clippy -D warnings, cargo test, and vitest (231) via the pre-commit hook.

🤖 Generated with Claude Code

read_file/write_file/delete_file were unconstrained filesystem
primitives reachable from the frontend and — via the quill:// deep
link — indirectly from any web page. A crafted path could read
/etc/passwd or overwrite an arbitrary file.

- ensure_allowed_path confines the three commands to Markdown
  documents and their .comments.json sidecars, the only paths any
  legitimate caller uses. The native open/save dialogs already
  restrict the user to .md, so no real capability is lost.
- parse_quill_open now resolves the decoded path and accepts it only
  if it canonicalizes to an existing regular .md/.markdown file
  (symlink re-checked), so a hostile quill://open?file=/etc/passwd
  can no longer coax Quill into touching arbitrary files.

Adds unit coverage for the path policy, the confined commands, and
deep-link target validation (existing file, missing file, non-Markdown
target, directory-with-.md-suffix, wrong host).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sam-powers sam-powers merged commit c9cf554 into main Jun 13, 2026
3 checks passed
@sam-powers sam-powers deleted the security/confine-file-commands branch June 13, 2026 21:53
sam-powers added a commit that referenced this pull request Jun 13, 2026
Documents Quill's security posture for a reviewing engineer: the threat
model (deep link as the one attacker-influenced entry point; deserialized
data trusted more than rendered data), the four merged hardening measures
(#57 path confinement + deep-link validation, #58 annotation sanitization,
#59 URL scheme allowlists, #60 binary-resolution hardening), and the two
deliberate non-fixes left in place with rationale (asset-protocol $HOME/**
scope, remote-image beacon).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant