Skip to content

security: replace JSONP feeds with server-side proxies and harden links#95

Open
sudhirl-droid wants to merge 4 commits into
feature_website-revampfrom
security/feed-proxy-hardening
Open

security: replace JSONP feeds with server-side proxies and harden links#95
sudhirl-droid wants to merge 4 commits into
feature_website-revampfrom
security/feed-proxy-hardening

Conversation

@sudhirl-droid

@sudhirl-droid sudhirl-droid commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Security: replace JSONP feeds with server-side proxies + harden feed-derived content

Summary

Removes the browser-side JSONP loading of the Blogger news/careers feeds — a remote-code-execution/XSS vector — and replaces it with same-origin Netlify Function proxies that return plain JSON. Adds defense-in-depth around feed-supplied links/images and tightens the site CSP. Also adds durable edge caching so the proxies are cheap and abuse-resistant.

Why

The site previously injected <script src="https://www.blogger.com/..."> (JSONP) to load feeds, which executes whatever the remote server returns inside our origin. Any compromise of the feed host, or a MITM, becomes script execution on our site. This PR eliminates that class of risk.

Changes

1. Server-side feed proxies (no more JSONP)

  • New netlify/functions/news-feed.mjs and careers-feed.mjs fetch the Blogger feeds server-side and return plain JSON. The browser only ever reads data.
  • Destinations are hard-coded (no SSRF); the only accepted inputs are a region validated against an allow-list and integer params that are parsed + clamped.
  • fetchNews / fetchOpenings rewritten to fetch() the same-origin proxies; all JSONP loader code deleted.

2. Link/URL hardening

  • New safeHttpUrl() helper returns a URL only if it is http(s):, blocking javascript: and other schemes arriving from feed data. Applied to all feed-supplied links and image URLs.
  • DOMPurify afterSanitizeAttributes hook forces rel="noopener noreferrer" on every target="_blank" link in sanitized job HTML (reverse-tabnabbing).

3. CSP tightening

  • script-src reduced from 'self' https://www.blogger.com https://news.maqsoftware.com'self' (possible now that JSONP is gone).

4. Edge caching (cost / DoS hardening)

  • Both proxies set Netlify-CDN-Cache-Control: public, s-maxage=300, durable, so identical requests are served from Netlify's edge for 5 minutes — cutting function invocations and upstream Blogger load, and absorbing most repeat/abusive traffic before it reaches the function.

5. Build config

  • Register netlify/functions (esbuild bundler) and pin NODE_VERSION = 20.

Security impact

  • ✅ Eliminates JSONP RCE/XSS vector
  • ✅ No SSRF (hard-coded hosts, validated/clamped inputs)
  • ✅ Blocks javascript: / non-http(s) links & images from feeds
  • ✅ Reverse-tabnabbing protection on sanitized links
  • ✅ Stricter CSP script-src 'self'
  • ✅ Feed HTML still sanitized via existing DOMPurify allow-list before render

Testing

  • tsc --noEmit and npm run build pass.
  • Branch reverse-merged with latest feature_website-revampno conflicts.

Notes / follow-ups (not in this PR)

  • Optional: add an AbortController timeout on the upstream fetch (return 504 if Blogger hangs).
  • Optional: per-IP rate limiting via a Netlify Edge Function if deliberate abuse becomes a concern (edge caching already covers most repeat traffic).

Files changed

  • netlify/functions/news-feed.mjs
  • netlify/functions/careers-feed.mjs
  • netlify.toml
  • src/data/news.ts
  • src/data/careers.ts
  • src/lib/url.ts
  • src/lib/sanitizeHtml.ts

- Add Netlify Function proxies (news-feed, careers-feed) that fetch the Blogger feeds server-side and return plain JSON, eliminating browser-side JSONP and the associated remote-code-execution (XSS) risk. Inputs are validated/clamped and destinations are hard-coded (no SSRF).
- Rewrite fetchNews/fetchOpenings to read JSON from the same-origin proxies; remove the JSONP loaders.
- Add safeHttpUrl() and apply it to all feed-supplied links and image URLs to block javascript: and other non-http(s) schemes.
- Add a DOMPurify hook forcing rel=noopener noreferrer on target=_blank links in sanitized job HTML.
- Tighten CSP script-src to 'self' (drop blogger.com / news.maqsoftware.com); register functions dir; pin NODE_VERSION 20.
Add Netlify-CDN-Cache-Control (s-maxage=300, durable) to news-feed and careers-feed so identical requests are served from the edge for 5 minutes. This cuts function invocations and upstream Blogger load, which also absorbs most abusive/repeat traffic before it reaches the function.
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