Skip to content

speakr

v0.8.21-alpha Security

This release includes 1 security fix for security teams reviewing exposed deployments.

Published 8d Productivity & Wikis
✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →
This release patches 1 known CVE

Affected surfaces

auth

ReleasePort's take

Moderate signal
editorial:auto 8d

The release patches two critical security flaws: a CSRF bypass via unauthenticated API token handling and a chained SSO‑only account takeover in the /change_password route.

Why it matters: Both vulnerabilities carry severity 95; patching immediately prevents unauthorized access for all users interacting with API tokens or password change flows.

Summary

AI summary

CSRF bypass and chained SSO-only account takeover vulnerabilities are fixed.

Changes in this release

Security Critical

Fixes CSRF bypass via unauthenticated API token parameter (GHSA-x4q4-3ww4-h329).

Fixes CSRF bypass via unauthenticated API token parameter (GHSA-x4q4-3ww4-h329).

Source: llm_adapter@2026-06-05

Confidence: high

Security Critical

Prevents chained SSO-only account takeover in /change_password endpoint.

Prevents chained SSO-only account takeover in /change_password endpoint.

Source: llm_adapter@2026-06-05

Confidence: high

Dependency Low

No dependency changes introduced in this release.

No dependency changes introduced in this release.

Source: llm_adapter@2026-06-05

Confidence: low

Bugfix High

Adds per‑request CSRF token validation using header authentication only; query‑string tokens are rejected.

Adds per‑request CSRF token validation using header authentication only; query‑string tokens are rejected.

Source: llm_adapter@2026-06-05

Confidence: high

Bugfix Medium

Updates /forgot-password to support password reset for SSO‑only users via email.

Updates /forgot-password to support password reset for SSO‑only users via email.

Source: llm_adapter@2026-06-05

Confidence: high

Refactor Low

Disables Flask‑WTF automatic CSRF check (`WTF_CSRF_CHECK_DEFAULT = False`) and uses custom wrapper.

Disables Flask‑WTF automatic CSRF check (`WTF_CSRF_CHECK_DEFAULT = False`) and uses custom wrapper.

Source: llm_adapter@2026-06-05

Confidence: high

Full changelog

v0.8.21-alpha — Security: CSRF bypass + chained SSO-only account takeover

Security patch release on top of v0.8.20-alpha. All users should upgrade promptly. Tracked as GitHub Security Advisory GHSA-x4q4-3ww4-h329.

Fixed

  • CSRF bypass via the unauthenticated API token parameter (CWE-287, CVSS 7.1). The csrf_exempt_for_api_tokens before_request hook called csrf.exempt(view_func) from inside a request handler whenever the request carried a token-shaped value, without validating the token against the database. Two consequences:

    • csrf.exempt() mutates Flask-WTF's process-global _exempt_views set permanently, so the exemption persisted for the lifetime of the worker — one bogus request was enough to disable CSRF on the targeted endpoint indefinitely.
    • The query-string token (?token=...) can be set by a Simple Cross-Origin Request without triggering CORS preflight, so a victim's browser could be tricked into making the disabling request from an attacker-controlled page.
    • Chained with the next finding, this enabled remote modification of arbitrary user state from a cross-origin attacker page: changing summary prompts, transcription settings, even toggling admin privileges.

    The hook is gone. CSRF skipping is now a per-request decision made by a new csrf_token_aware_check before_request handler that calls a new load_user_from_token_headers_only() helper. That helper hashes the token, looks it up in the database, and checks is_valid(), and only accepts the token from the three request headers (Authorization, X-API-Token, API-Token) — never from the query string. Flask-WTF's automatic CSRF check is disabled (WTF_CSRF_CHECK_DEFAULT = False) so only our wrapper runs.

  • Chained SSO-only account takeover in /change_password. When current_user.password was None (every SSO-only account), the current-password check was skipped and the route silently set a new password. Combined with the CSRF bypass above, this allowed an attacker to set a password on a victim's SSO-only account from a cross-origin page and then log in directly with the new credentials, bypassing SSO entirely. The route now refuses to act on accounts with no existing local password and directs users to the password-reset flow instead. To preserve the legitimate "add a password so I can later unlink SSO" workflow, /forgot-password now also issues reset emails for SSO-only users; the user's email account is the proof-of-ownership gate (the same trust boundary every password-reset flow uses), so the takeover is closed while the flow keeps working.

Tests

tests/test_csrf_token_bypass_fix.py — 12 regression tests covering both attacks from the advisory and the backwards-compat surfaces: query-string and header fake-token rejection, the valid-header-token per-request bypass, the valid-query-string-token-on-non-v1 rejection, the SSO-only change_password refusal, the end-to-end SSO-only-add-password flow via forgot_password, the SMTP-not-configured safety net, all four documented API token methods on /api/v1/*, the ?token= POST on /api/v1/* (preserved by blueprint-level exemption), the browser session POST with a valid CSRF token, the change_password happy path for users with an existing password, and the Authorization: Bearer POST on /api/v1/*. The exempt-set immutability is asserted before and after each attempted bypass.

Credits

Reported privately under GitHub's Private Vulnerability Reporting by @Irench1k. Thank you for the detailed report, the working proof-of-concept, and the patience while the disclosure timeline aligned.

Migration

No configuration changes are required. Existing API-token automation continues to work via the v1 endpoints (still blueprint-level CSRF-exempt) and via header authentication on any other endpoint. Automation that relied on the ?token=... query parameter to bypass CSRF on state-changing requests will need to switch to header authentication; this was always the documented method.

Upgrade is the usual docker compose pull && docker compose up -d.

Breaking Changes

  • Removed `csrf_exempt_for_api_tokens` before_request hook; query-string token bypass (`?token=`) no longer disables CSRF.

Security Fixes

  • GHSA-x4q4-3ww4-h329 — Fixed CSRF bypass (CWE-287, CVSS 7.1) via unauthenticated API token parameter and chained SSO-only account takeover in `/change_password`.

Weekly OSS security release digest.

The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.

No spam, unsubscribe anytime.

Share this release

Track speakr

Get notified when new releases ship.

Sign up free

About speakr

Speakr is a personal, self-hosted web application designed for transcribing audio recordings

All releases →

Beta — feedback welcome: [email protected]