AnchorCast v1.4.0
AnchorCast v1.4.0 — Security & Bug Fix Release
🔒 Security Hardening + 🐞 Bug Fixes
This release combines a full security audit of the v1.3.0 codebase with several bug fixes discovered during testing. No new features.
If you run AnchorCast with the Remote Control enabled or on a shared network, this update is strongly recommended.
🚨 Critical Fixes
- Settings API exposed credentials —
GET /api/settingsreturned stored API keys (Claude, Deepgram, Genius) and all remote control PINs to any device on the same Wi-Fi with no authentication. Sensitive fields are now stripped for non-local callers - Settings API open to writes — Any LAN device could overwrite all app settings (including changing PINs or API keys) via
POST /api/settingswith no authentication. Now protected - External URL injection — The
open-externalIPC handler accepted any URL scheme, allowing a malicious payload to launchfile://,ms-msdt://, or other system protocol handlers. Now restricted tohttps:,http:, andmailto:only
⚠️ High Severity Fixes
- Same-origin policy was disabled — Both the main window and projection window had
webSecurity: false, disabling the browser's cross-origin protections. Removed from both windows; local media files continue to load via themedia://protocol - Arbitrary file read via
media://— The custom media protocol had no path restriction and would serve any file on the filesystem. Now restricted to the AnchorCast data directory and app assets - Remote PINs stored in plaintext — PINs were saved as plain text in
settings.jsonand compared with simple string equality. Now hashed with PBKDF2 (SHA-256, 100k iterations, unique salt per PIN) and compared in constant time. Existing PINs migrate automatically on next save — no action needed - Presentation import command injection —
import-presentationpassed a caller-supplied file path into a PowerShell command string with insufficient escaping. File path is now resolved, validated, and passed as a positional argument — never interpolated into a command string
🛡️ Medium Severity Fixes
- Projection control API unauthenticated —
POST /api/control(which drives the live projection display) required no token or PIN. Any device on the local network could project arbitrary content mid-service. Now protected - Whisper server reinforcement endpoint unauthenticated — Any local process could inject arbitrary text into the Whisper AI context window, biasing live transcription output. The Whisper server now requires a per-run shared secret on every request
- Whisper server memory exhaustion — The
/transcribeendpoint had no payload size limit and no lock timeout. Now enforces a 10 MB cap and 30-second timeout - XSS in live transcript display — Whisper interim transcript text was rendered directly into
innerHTML. Fixed - XSS in service replay timeline — Archived service payload data (verse refs, song titles, transcript text) rendered unescaped. Fixed
- XSS in HTML renderer pages — Six renderer HTML files had user-derived strings injected raw into
innerHTML. All patched withescH()escaping - Song lyric sanitizer bypassable — The projection HTML sanitizer missed unquoted event handlers,
style=url(javascript:...), and backtick-quoted attributes. Hardened to cover all cases
📋 Other Security Fixes
- Remote session token moved from
localStoragetosessionStorage— clears when the browser tab is closed - NSIS installer scripts now use
GetTempFileName— prevents TOCTOU race on predictable temp paths - VC++ fallback download now verified with SHA-256 before execution
- Content-Security-Policy headers added to all Express HTTP responses
"asar": trueexplicitly set in all electron-builder configs- Electron upgraded from v31 (EOL) to v33
🐞 Bug Fixes
- macOS: Black screen on relaunch — Closing AnchorCast with Cmd+Q then reopening from the Dock showed a blank dark window. The renderer HTTP server was shut down on quit but macOS kept the process alive — when re-opened, the main window loaded against a dead server port and silently stayed black. The
activatehandler now restarts the renderer server automatically before creating windows - macOS: Splash screen stuck on Dock relaunch — Clicking the Dock icon after closing showed the splash progress bar indefinitely. Stale window refs and state were not reset between close and reactivate. Full reset added with a 12-second fallback timeout so the splash never hangs forever
- macOS: "Could not check for updates" HTTP 404 — The update checker requested
latest-mac-arm64-mac.yml(double-macsuffix) instead oflatest-mac-arm64.yml. Corrected to match what electron-builder actually publishes - Media import silently failing — Removing
webSecurity: false(security fix) causedfile.pathto stop being populated on File objects from drag-and-drop. Files appeared to be accepted but nothing was imported. Fixed usingwebUtils.getPathForFile()— the correct Electron API — exposed via preload - PowerPoint import failing on Windows — The PowerShell injection fix changed to
param()+-Args, but-Argsonly works with-File, not-Command.$srcwas always empty, causing a COM error. Script is now written to a temp file and run with-File+ positional arguments - Remote control Copy URL / Share not working —
navigator.clipboardrequires HTTPS. The remote runs onhttp://192.168.x.xso clipboard writes silently failed. Fixed with a 3-method fallback that works on any HTTP origin - Remote control showing "Error 429" — A stale session token caused repeated auth failures, triggering a rate limit. The raw HTTP code was shown with no guidance. All remote error responses now show friendly messages; 401 and 429 both show the PIN entry screen automatically
- Deepgram false "Invalid API key" toast — When Deepgram was selected as the transcript source, the main process still tried to process audio chunks and fired
transcript-no-keywhen it had no handler for thedeepgramsource. Added guard to skip main-process chunk handling when Deepgram is active - Sermon Notes limited to ~5 points —
max_tokens: 2000caused the JSON response to be silently truncated for longer sermons. Increased to4096with explicit prompt instruction to capture all points
📦 Downloads
| Platform | Variant | Description |
|---|---|---|
| Windows | Full | Includes Python + Whisper model (~600 MB) — ready to use offline immediately |
| Windows | Light | Includes Python only (~200 MB) — downloads Whisper model on first use |
| macOS Apple Silicon | Full | For M1/M2/M3 Macs with model bundled |
| macOS Apple Silicon | Light | For M1/M2/M3 Macs, downloads model on first use |
| macOS Intel | Full | For Intel Macs with model bundled |
| macOS Intel | Light | For Intel Macs, downloads model on first use |
Upgrading from v1.3.0? Your data, settings, Whisper models, songs, transcripts, and schedules are fully preserved. Remote control PINs will be re-hashed automatically on first settings save — you do not need to re-enter them.
Upgrading from v1.2.0 or earlier? See the v1.3.0 release notes for full migration details first.