Skip to content

chore: add CSP header; route unwatch-file through path-guard#3

Merged
ivandobskygithub merged 1 commit into
mainfrom
chore/csp-and-unwatch-guard
May 6, 2026
Merged

chore: add CSP header; route unwatch-file through path-guard#3
ivandobskygithub merged 1 commit into
mainfrom
chore/csp-and-unwatch-guard

Conversation

@ivandobskygithub

Copy link
Copy Markdown
Owner

Summary

Closes the only real gap found auditing upstream security PRs doctly#27 and doctly#32 against this fork's existing hardening.

What this PR adds

  1. Content-Security-Policy on every renderer response.

    • default-src 'self'
    • script-src 'self' (no unsafe-inline/unsafe-eval — markdown goes through DOMPurify before hitting the DOM)
    • style-src 'self' 'unsafe-inline' — xterm injects per-cell colour styles via `setAttribute('style', …)` at runtime; this is required.
    • img-src 'self' data: blob: — for icons and any avatars/screenshots.
    • object-src 'none', base-uri 'self', frame-ancestors 'none'.
  2. unwatch-file IPC now routes through assertPathAllowed, matching the rest of the file IPC surface. Not a real escalation fix (a renderer can only ever close a watcher it opened) — consistency.

What we did NOT pull from doctly#27 / doctly#32 (already covered)

Upstream item Status in this fork
Path-guard on read-file-for-panel, save-file-for-panel, watch-file, read-memory, save-memory ✅ already wired through path-guard.js
DOMPurify on marked.parse() output ✅ already done (commit a8bf6ca)
permissionMode / worktreeName / addDirs validation ✅ already in claude-cmd.js (regex-validated, shell-quoted)
Scheduler shell injection — frontmatter values into bash ✅ already shell-quoted with regex validation per field (PERMISSION_MODES, MODEL_RE, BUDGET_RE, ALLOWED_TOOL_NAMES); upstream's argv refactor would be more defensive but functionally equivalent given correct `shq`
MCP lock file 0o600 ✅ already in mcp-bridge.js:341
claude-auth.js keychain execSyncexecFileSync N/A — file does not exist in this fork

Test plan

  • npm test → 145/145 passing
  • Smoke test: launch app, open a project, render markdown plan/memory (CSP shouldn't block)
  • Smoke test: open file in viewer panel; xterm styles should still render
  • DevTools console: no CSP violation reports

🤖 Generated with Claude Code

CSP: default-src 'self' with allowances for xterm's runtime inline styles
(style-src 'unsafe-inline'), data: imgs, and data: fonts. No 'unsafe-inline'
or 'unsafe-eval' for scripts — markdown is sanitised through DOMPurify
before hitting the DOM.

unwatch-file: route the path through assertPathAllowed so the IPC surface
is uniform with watch-file / read-file-for-panel / save-file-for-panel.
A renderer can only ever close a watcher it could have opened anyway, so
this is consistency rather than a real escalation fix.

Identified during a follow-up audit against upstream PR #27. The other
items in #27 (path-guard on file IPCs, DOMPurify on markdown, scheduler
shell-quoting) are already in place via earlier hardening commits.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@ivandobskygithub ivandobskygithub merged commit 2fe6402 into main May 6, 2026
@ivandobskygithub ivandobskygithub deleted the chore/csp-and-unwatch-guard branch May 6, 2026 08:11
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