Skip to content

fix(matrix): restore conservative Synapse rc_login limits + operator password floor#173

Draft
ndee wants to merge 1 commit into
mainfrom
fix/167-synapse-rc-login
Draft

fix(matrix): restore conservative Synapse rc_login limits + operator password floor#173
ndee wants to merge 1 commit into
mainfrom
fix/167-synapse-rc-login

Conversation

@ndee

@ndee ndee commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Problem

The generated homeserver.yaml hard-codes rc_login to per_second: 1000 / burst_count: 1000 for address, account, and failed_attempts — effectively disabling login brute-force protection.

This matters because:

  • Synapse's /_matrix/client/v3/login is reverse-proxied on the public hostname / LAN (Caddy catch-all → synapse:8008).
  • The operator's Matrix password is the same credential the setup UI accepts (verifyOperatorPassword POSTs to that endpoint).
  • The API-layer rate limiter doesn't protect this path — an attacker hits Synapse directly.

So an attacker on the LAN (or the internet in relay/public-TLS modes) could iterate a password list against /login with no throttling or lockout and, on success, obtain a full operator/homeserver-admin token.

Fix

  • Restore conservative rc_login limits — Synapse defaults per_second: 0.17, burst_count: 3 for address, account, and failed_attempts. This re-enables sustained-rate throttling (~10/min) and lockout on failed attempts.
  • Operator password floor — require a minimum length of 12 when an operator password is supplied at install time (operatorInstallInputSchema). Login verification (contracts/auth.ts) deliberately keeps min(1) so already-provisioned operators are never locked out by this tightening.

Tests

  • src/system/matrix.test.ts: assert the conservative limits are rendered and that 1000/1000 is not present.
  • src/contracts/install.test.ts: new operatorInstallInputSchema cases (omitted password ok, at-minimum ok, below-minimum rejected).
  • biome lint, tsc --noEmit, and the full unit suite (201 tests) pass locally.

Notes

  • Upgrade-safe: existing installs regenerate homeserver.yaml with the new limits on next provision; the password floor only gates new install-time input.
  • End-to-end install validation on an ephemeral VM is being run alongside the related installer hardening change before these are marked ready.

…password floor

The generated homeserver.yaml hard-coded rc_login to per_second: 1000 /
burst_count: 1000 across address, account, and failed_attempts, which
effectively disables login brute-force protection. Synapse's
/_matrix/client/v3/login is reverse-proxied on the public hostname and
LAN, and the operator's Matrix password is the same credential the setup
UI accepts, so an attacker could brute-force the operator credential
directly against Synapse with no throttling or lockout.

- Set rc_login limits to Synapse's conservative defaults
  (per_second: 0.17, burst_count: 3) for address, account, and
  failed_attempts, restoring brute-force throttling/lockout.
- Require a minimum length (12) for the operator password when supplied
  at install time (operatorInstallInputSchema). Login verification keeps
  min(1) so already-provisioned operators are never locked out.
- Update matrix.test.ts to assert the conservative limits ship (and that
  1000/1000 never does); add operatorInstallInputSchema unit tests.

Validated: biome lint, tsc, and the full unit suite (201 tests) pass.
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