The pattern /worldmonitor.*\.vercel\.app/ matched any Vercel deployment
with a "worldmonitor" prefix, allowing unauthorized origins to bypass
CORS and consume server-side API keys. The owner-scoped pattern on the
previous line already covers all legitimate preview deployments.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Save keys that pass verification even when others fail (was all-or-nothing)
- Capture un-blurred input values before render to prevent loss on checkbox toggle
- Fix missing isDisallowedOrigin import in PIZZINT endpoints
Replace Access-Control-Allow-Origin: * with shared getCorsHeaders()
across 20 API edge functions to restrict access to worldmonitor.app,
tech.worldmonitor.app, and authorized Vercel preview URLs.
Version bump to 2.2.5 across package.json, tauri.conf.json, Cargo.toml.
ipwho.is returns 403 from Node.js/Edge ("CORS not supported on Free plan")
and ipapi.co rate-limits aggressively (429). Both providers only work from
browser-side requests.
Switch to ipinfo.io (HTTPS, 50K/mo free, works from Edge runtime) as primary
with freeipapi.com as fallback.
Validated end-to-end: 20 C2 IPs geo-enriched in <1s with real coordinates.
Expands from 2 to 5 threat intel sources:
- C2IntelFeeds (free, no auth): ~500 active C2 server IPs (CobaltStrike, Metasploit)
- AlienVault OTX (optional API key): community-sourced IOCs with tags
- AbuseIPDB (optional API key): high-confidence abuse reports with geo
- Feodo: now includes recently-offline entries (still threat-relevant)
All sources fetched in parallel. Graceful degradation when API keys missing.
Plot live botnet C2 servers, malware distribution nodes, and malicious IPs
on the globe using free abuse.ch APIs (Feodo Tracker + URLhaus).
- Vercel edge API with triple-layer caching (Redis → memory → stale fallback)
- IP geolocation via ipwho.is + ipapi.co (HTTPS-compatible with Edge runtime)
- Severity-based color coding (critical=red, high=orange, medium=amber, low=yellow)
- Feature-gated behind VITE_ENABLE_CYBER_LAYER=true env var
- Frontend circuit breaker, data sanitization, 10min auto-refresh
- Tauri desktop support: 3 new secret keys (URLHAUS, OTX, AbuseIPDB)
- Full test suite (6 unit tests), e2e harness updates, popup + tooltip rendering
Edge function that redirects /api/download?platform=macos-arm64 to
the matching asset from the latest GitHub release. Falls back to
the releases page when no match is found.
Switch bridge page from raw iframe to YouTube IFrame Player API with
postMessage protocol for play/pause/mute commands. Use youtube-nocookie.com
host, add click-to-play overlay for WKWebView autoplay restrictions, and
route desktop embeds through cloud URL to avoid sidecar auth issues.
- Add RUSI, Wilson Center, GMF, Stimson, CNAS, Lowy Institute feeds
- Add Arms Control Association, Bulletin of Atomic Scientists feeds
- Add FAO GIEWS food security alerts, EU ISS feeds
- Add www.iss.europa.eu to RSS proxy allowlist
- Add SOURCE_TIERS and SOURCE_TYPES entries for new feeds
- Fix YouTube Error 153 by serving embed bridge from cloud URL (origin match)
- Fix channel switching when playerContainer detached from DOM
- Fix Fires panel infinite spinner when API returns 0 or fails
- Make TECH variant button open web URL instead of being disabled
- Fix circuit breaker caching empty results as success in 6 services
(polymarket, wingbits, military-flights, outages, conflicts, protests)
- Improve sidecar: cloud-preferred routing, failed import caching, log dedup
- Add FINNHUB_API_KEY and NASA_FIRMS_API_KEY to Tauri secret keys
- Add early 503 for missing ACLED token in risk-scores
- Add /api/classify-batch endpoint: classifies up to 20 headlines per Groq call
(reduces 182 individual API calls to ~10 batched calls, 90% rate limit savings)
- Update threat-classifier.ts: collect headlines in batch queue, flush every 500ms
or when batch reaches 20 items
- Route AIS snapshot through Railway directly when VITE_WS_RELAY_URL is set,
falling back to Vercel — eliminates 503 when WS_RELAY_URL not configured on Vercel
- Add /ucdp-events handler to ais-relay.cjs with 6h TTL cache,
background refresh, version discovery, and 30s per-page timeout
- Route client through Railway when VITE_WS_RELAY_URL is set
- Add 8s AbortController timeout to Vercel fallback fetchGedPage()
- Extract close price arrays from Yahoo Finance chart API for indices/commodities
- Switch CoinGecko crypto fetch to /coins/markets endpoint with 7d sparkline data
- Render inline SVG sparklines color-coded green/red by price direction
- Fix Vite dev proxy for CoinGecko (was hitting root instead of /api/v3/simple/price)
- Add endpoint=markets support to CoinGecko edge function
Three new crypto/market intelligence panels with self-fetching data:
- Market Radar (macro-signals): 7 signals from Yahoo Finance, mempool.space,
alternative.me — liquidity, flow structure, macro regime, BTC trend with
30d VWAP, hash rate, mining cost, fear & greed. SVG sparklines and donut gauge.
- BTC ETF Tracker (etf-flows): 10 spot Bitcoin ETFs via Yahoo Finance 5-day
chart with estimated net flows, volume, and price change per ETF.
- Stablecoins (stablecoin-markets): CoinGecko proxy for peg health monitoring
(ON PEG / SLIGHT DEPEG / DEPEGGED) and supply/volume breakdown.
All endpoints include CORS origin guard, input validation, in-memory caching
with stale fallback. Panels registered in both full and tech variants.
UCDP API fields are conflict_id, location, side_a, intensity_level etc.
(snake_case) — proxy was reading ConflictId, Location, IntensityLevel
(PascalCase), causing all values to be empty/0.
Also paginate through all results instead of just first page.
- Chatham House RSS returns 403 from cloud IPs, use Google News fallback
- FAO FPMA feed returns HTML (Angular app), not RSS — replaced with fao.org/rss
- Updated rss-proxy allowlist domain
- Endpoint was conflict-event (singular), fixed to conflict-events (plural)
- app_identifier must be base64("name:email"), passed as query param
- Response fields are (events, fatalities, event_type) per row, not
pre-aggregated columns — fixed aggregation logic
- Remove Arab News and Times of Israel feeds (403 from cloud IPs)
Replace hardcoded conflict floor scores with real data from three sources:
- ACLED battles/explosions/violence against civilians (30-day events)
- UCDP conflict classification (war vs minor vs none, data-driven floors)
- HDX HAPI aggregated monthly conflict counts (fallback/validation)
New CII component 'conflict' weighted 30% of event score. Updated formula:
unrest(25%) + conflict(30%) + security(20%) + information(25%)
- Gradient background with left accent sidebar in level color
- Large 120px CII score with /100 + labeled score bar with tick marks
- Semicircle arc gauge on right with score + level badge
- Data indicator legend (threat, military, markets, convergence, signals)
- No-score fallback shows 4 feature cards with descriptions
- Bottom bar with W logo circle, brand text, and CTA button
- Subtle grid background, status pill, date stamp
- Story renderer: larger fonts, better contrast (#777 vs #555 headers,
#e0e0e0 vs #ddd text), visible separators (#222 vs #1a1a2e), removed
grid background noise, bigger score (72px), bigger headlines (26px)
- OG image: pass score & level params to og-story endpoint, improve
contrast, larger score text (96px), better fallback when no score
- Meta tags: include s= and l= query params in og:image URL
- /api/og-story: generates SVG OG image with country name, CII score, level
- /api/story: serves meta tags to social crawlers, redirects real users to SPA
- Deep links now point to /api/story for proper crawler support
- Pass CII score/level through URL params for dynamic OG images
- Add NASA FIRMS satellite fire detection map layer and panel
- Add temporal baseline anomaly detection (Welford's algorithm, Redis-backed)
- Wire signal aggregator with fires, temporal anomalies
- Remove 10 dead service files and unused markdown docs
- Deduplicate RSS feeds, clean up story templates
- Fix data freshness, status panel, and verification checklist
- Create og-image.png for social sharing meta tags
- Update README with signal aggregation, source tiering, edge architecture
- Bump version to 2.1.4
Thresholds were calibrated for classified-level data visibility (50+ aircraft for
Iran ELEVATED). Open-source trackers (OpenSky/Wingbits) see ~10-20% of actual
military flights. Lowered all theaters ~5-6x to match real detection rates.
Added localStorage persistence to cached-theater-posture so the Strategic Posture
panel shows last-known data instantly on page reload instead of starting empty.
Switch from volume-only market fetching to tag-based event queries
for better relevance. Variant-aware tags (geopolitical vs tech).
Deduplicates across tag queries, falls back to top-volume markets
only when needed. Add clickable links to Polymarket event pages.
- Add DFMGI.AE for UAE (DFM General Index)
- Use range=1mo instead of 5d to handle Sun-Thu trading weeks
- Take last ~5 trading days from monthly data for weekly % change
- Remove broken Qatar symbol (^QSI returns no data)