fix: harden security across API, desktop, and frontend layers#233
fix: harden security across API, desktop, and frontend layers#233bperkins-oss wants to merge 1 commit intokoala73:mainfrom
Conversation
- Remove Cargo.lock from .gitignore for reproducible Rust builds - Add domain allowlist to sidecar RSS proxy (prevents SSRF) - Apply encodeURIComponent to ArXiv proxy params (prevents injection) - Remove GOPROXY=direct to restore Go checksum verification - Add security headers (HSTS, X-Frame-Options, X-Content-Type-Options) - Replace weak PID+timestamp token with CSPRNG (/dev/urandom) - Fix CORS wildcard fallback and version endpoint to use explicit origin - Remove overly broad Vercel preview CORS pattern from YouTube embed - Validate YouTube channel param with strict regex - Validate download redirect URL is on github.com - Fix postMessage wildcard origin in YouTube embed - Add origin validation to embed message listener - Remove style from safeHtml allowlist (prevents CSS injection) - Replace inline onclick with addEventListener (CSP-compatible) - Escape e.method in traffic log table (XSS defense-in-depth) - Redact apiDir from sidecar status endpoint Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@bperkins-oss is attempting to deploy a commit to the Elie Team on Vercel. A member of the Team first needs to authorize it. |
koala73
left a comment
There was a problem hiding this comment.
Security Hardening Review — 3 Blocking Issues
Most fixes are correct and close real vulnerabilities. However, there are critical problems that will break functionality.
BLOCKING
1. X-Frame-Options: DENY breaks YouTube embed iframe
vercel.json applies X-Frame-Options: DENY to /(.*) which includes /api/youtube/embed — the HTML page loaded in an iframe by LiveNewsPanel. Browsers will refuse to render it. Either use SAMEORIGIN globally or exclude the embed route from the header.
2. ArXiv encoding will likely break search
list-arxiv-papers.ts now does:
searchQuery = `all:${encodeURIComponent(req.query)}+AND+cat:${encodeURIComponent(category)}`;The +AND+ is an ArXiv query operator mixed with half-encoded components. Use URLSearchParams to encode the full search_query parameter properly instead:
const params = new URLSearchParams({
search_query: searchQuery,
start: '0',
max_results: String(pageSize),
});
const url = `https://export.arxiv.org/api/query?${params}`;3. Security headers in middleware are dead code
SECURITY_HEADERS in middleware.ts is only spread into the 403 bot-block responses. Normal requests pass through without them. The vercel.json headers cover real traffic, so the middleware code gives a false sense of coverage. Remove it from middleware (rely on vercel.json) or apply via NextResponse.next().
SUGGESTIONS
4. Token generation doesn't use CSPRNG on Windows
main.rs reads /dev/urandom which doesn't exist on Windows. Fallback is still the weak PID+timestamp hash. Use getrandom::getrandom(&mut buf) for cross-platform CSPRNG — it's already in Rust's dependency tree.
5. RSS allowlist is duplicated (~100 lines)
Sidecar now has a copy-pasted RSS_ALLOWED_DOMAINS that mirrors api/rss-proxy.js. No mechanism keeps them in sync. Extract to a shared JSON file or at minimum add "KEEP IN SYNC with api/rss-proxy.js" comments in both files.
6. showEmbedError still uses inline patterns
PR fixes showOfflineMessage to use addEventListener but showEmbedError in the same file still uses innerHTML + template literal pattern. Inconsistent.
7. e.status and e.durationMs not escaped in settings-main.ts
Same defense-in-depth reasoning that motivated escaping e.method applies to these numeric fields — coerce with ${Number(e.status)} or escapeHtml().
Good Changes (no issues)
- CORS wildcard → explicit origin in catch blocks ✓
- Sidecar RSS domain allowlist (closes SSRF) ✓
- YouTube postMessage wildcard → validated origin ✓
- YouTube channel parameter validation ✓
- Download redirect URL validation ✓
- Removing
GOPROXY=direct✓ - Removing
apiDirfrom sidecar status ✓ - Committing
Cargo.lock✓ - Removing
stylefromsafeHtmlallowlist ✓ - Inline
onclick→addEventListener✓ - Escaping
e.method✓
Summary
Security audit identified several vulnerabilities across the API, desktop app, and frontend. This PR fixes 19 issues across 15 files:
Critical/High fixes:
Cargo.lockfrom.gitignorefor reproducible Rust buildsencodeURIComponentto ArXiv proxy params (prevents URL parameter injection)GOPROXY=directto restore Go checksum verificationvercel.jsonandmiddleware.ts/dev/urandom)Medium fixes:
https://github.com/stylefromsafeHtml()attribute allowlist (prevents CSS injection)apiDirfilesystem path from sidecar status endpointLow fixes:
postMessagewildcard origin in YouTube embed → use validated parent originmessageevent listeneronclickwithaddEventListener(CSP-compatible)e.methodin traffic log table (XSS defense-in-depth)Test plan
curl -I https://worldmonitor.appsafeHtml()tooltip rendering still works withoutstyleattribute🤖 Generated with Claude Code