You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SSRF hardening on authenticated browser navigation.save_post, unsave_post, and fetch_post_content (reachable from both the CLI and the MCP tools exposed to LLM clients) now reject any non-HTTPS URL via a new _require_https() guard before Playwright's authenticated browser context navigates to it. This closes a path where a caller-supplied URL — including one reachable via prompt injection into an LLM client — could reach file:// paths or internal/cloud-metadata HTTP endpoints (e.g. 169.254.169.254).
Session credential file hardening. The storage_state.json session file written during login is now pre-created with owner-only 0o600 permissions before Playwright populates it, closing a brief window where it could be created world/group-readable under a permissive umask. chmod failures on the credentials file and its parent directories are now logged instead of silently swallowed.
Dedup cleanup. Extracted _with_playwright() (shared Playwright instance dispatch), _resolve_row() (posts/notes URL-or-ID lookup), and _last_sync_info() (per-entity sync-status query) helpers, plus module-level STEALTH_LAUNCH_ARGS/STEALTH_CONTEXT_KWARGS constants, removing repeated logic across substack_client.py, database.py, and cli.py.