Four-part audit (OIDC/JWT/crypto, user sync, admin UI, login bypasses)
with dynamic PoCs against a real WordPress install; every fix is covered
by a regression test. Report: docs/security-audit.md, section 6.
Critical/High
- Multisite: settings, AJAX actions and certificate download require
manage_network_options (site admins could sign in as super admin).
- Privileged accounts are only linked (sync and first sign-in) via a
matching UPN of a member account, never via the settable mail
attribute; the sync never changes their e-mail address; e-mail change
notifications stay on.
- Button-only mode exempts by credential (application passwords, WP-CLI)
instead of request context, closing bypasses through xmlrpc.php and
REST login handlers; API requests never receive login cookies.
- Multi-tenant mode refuses guest/external identities.
Medium/Low
- Same message for right and wrong passwords; button-only no longer
switches off when the connection breaks; server-side fallback cookie
expiry; correct fallback key beats IP lockouts; right-most proxy hop;
higher start limit; one object ID per account.
- Deactivation sets a random password, revokes application passwords and
removes the role (restored on reactivation); disabled people are
deactivated even when their mail vanished; duplicate bindings handled.
- Sync: abort on empty directory answer, no deprovisioning right after a
tenant change, atomic run lock, strict photo path validation.
- Certificates: key bundles refused, clean re-exported certificate.
- Array-safe sanitising, encoded redirect_to, per-action nonces, escaped
role lists, no Graph sleeps during sign-in, warnings for public groups,
multi-tenant group rules and missing salts, uninstall clears the token.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Certificate (RFC 7523 client assertion) as an alternative to the client
secret: one-click generation of a 3072-bit RSA key pair with a
self-signed certificate, .cer download (public part only), own PEM
upload with validation, expiry display, encrypted key storage. Both the
authorization code exchange and the Graph client-credentials request
use the selected method. Step-by-step guides for secret, certificate
and the app registration are shown in the settings.
Security audit (docs/security-audit.md) and fixes:
- Multi-tenant mode ignored the unverified email claim: matching now
uses the UPN only, or the email claim when xms_edov is true.
- Login starts are rate limited per client (30 per 10 minutes).
- Optional trusted proxy header for client IPs
(M365_LOGIN_CLIENT_IP_HEADER / filter).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJxAHYdMfKPoN4koRc4Ci2