Skip to content

fix: resolve critical review findings (data race, permissions, goroutine leak, CSP) - #18

Open
jgardiner68 wants to merge 4 commits into
digisamroc:mainfrom
jgardiner68:fix/review-criticals
Open

fix: resolve critical review findings (data race, permissions, goroutine leak, CSP)#18
jgardiner68 wants to merge 4 commits into
digisamroc:mainfrom
jgardiner68:fix/review-criticals

Conversation

@jgardiner68

Copy link
Copy Markdown

Summary

Fixes the critical and high-severity findings from a full code review: a data race on job state, world-readable files containing personal data, a goroutine leak in the IMAP watcher, and a weak Content-Security-Policy relying on third-party CDNs.

Changes

Data race on Job fields (critical)

internal/web/server.go wrote Job.Sent, Failed, Progress, DailyLimit, DaySent, Status, and Error directly from the background send goroutine while HTTP handlers (/api/job/active, /api/job/{id}/status) read them concurrently through the mutex-guarded ToJSON. All writes now go through new locked methods on Job (Resume, SetDailyLimit, PauseForDailyLimit), and previously-unlocked reads in JobManager.GetActive, JobManager.Cleanup, and saveJobProgress now use locked accessors (GetStatus, finishedBefore).

File permissions on personal data (high)

  • History SQLite DB was created with umask-dependent permissions; it now gets chmod 0600 after creation (internal/history/history.go).
  • Browser screenshots capture opt-out forms filled with the user's personal data but were written 0644 in a 0755 directory; now 0600 in a 0700 directory (internal/browser/browser.go).

IMAP IDLE goroutine leak (high)

WatchForNewEmails returned on context cancellation without waiting for the IDLE goroutine to finish, leaking one goroutine (blocked on a channel send) per cancelled watch. It now drains idleDone after closing stop (internal/inbox/monitor.go).

CSP hardening (high)

  • Tailwind and HTMX are now self-hosted from /static/js/ instead of loaded from cdn.tailwindcss.com and unpkg.com — no third-party script execution, no usage leaked to CDNs. The Tailwind runtime was already vendored but misnamed static/css/tailwind.min.css (it's the JS Play CDN runtime); renamed to static/js/tailwind.min.js.
  • script-src drops the CDN hosts and 'unsafe-eval' (no template uses htmx's hx-on/js: eval features); added object-src 'none'.
  • 'unsafe-inline' is retained for now — templates use inline onclick handlers and script blocks; removing it needs a nonce-based refactor (follow-up).

Test plan

  • go build ./..., go vet ./... pass
  • go test -race ./... passes
  • Web UI verified in browser: pages render fully styled from local assets, HTMX loads, no console errors, no CSP violations
  • TODO: unit test exercising concurrent Job writes + ToJSON reads under -race
  • TODO: test asserting DB/screenshot file modes after creation
  • Manual: resume a paused send job and confirm progress counters restore correctly

Job.Sent/Failed/Progress, DailyLimit, DaySent, Status and Error were
written directly from the send goroutine while HTTP handlers read them
via the mutex-guarded ToJSON. Route all writes through new locked
methods (Resume, SetDailyLimit, PauseForDailyLimit) and add locked
reads (GetStatus, finishedBefore) for JobManager.GetActive, Cleanup
and saveJobProgress.
The SQLite history DB and browser screenshots both contain personal
data but were created with umask-dependent / world-readable modes.
Chmod the DB to 0600 after creation; write screenshots 0600 in a
0700 directory.
WatchForNewEmails returned on ctx.Done without waiting for the IDLE
goroutine to exit, leaking one goroutine (and its channel send) per
cancelled watch. Drain idleDone after closing stop.
Serve the Tailwind runtime and HTMX from /static/js instead of
cdn.tailwindcss.com and unpkg.com (the local Tailwind runtime was
already vendored but misnamed .css). Drop the CDN hosts and
'unsafe-eval' from script-src and add object-src 'none'.
'unsafe-inline' remains until inline handlers move to a nonce-based
setup.
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