Fix the findings of a full second security audit
Some checks are pending
CI / PHP lint (7.4) (pull_request) Waiting to run
CI / PHP lint (8.0) (pull_request) Waiting to run
CI / PHP lint (8.1) (pull_request) Waiting to run
CI / PHP lint (8.2) (pull_request) Waiting to run
CI / PHP lint (8.3) (pull_request) Waiting to run
CI / PHP lint (8.4) (pull_request) Waiting to run
CI / WordPress Coding Standards (pull_request) Waiting to run
CI / WordPress.org Plugin Check (pull_request) Waiting to run
Some checks are pending
CI / PHP lint (7.4) (pull_request) Waiting to run
CI / PHP lint (8.0) (pull_request) Waiting to run
CI / PHP lint (8.1) (pull_request) Waiting to run
CI / PHP lint (8.2) (pull_request) Waiting to run
CI / PHP lint (8.3) (pull_request) Waiting to run
CI / PHP lint (8.4) (pull_request) Waiting to run
CI / WordPress Coding Standards (pull_request) Waiting to run
CI / WordPress.org Plugin Check (pull_request) Waiting to run
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>
This commit is contained in:
parent
791f43a80b
commit
850f0dcd54
18 changed files with 1908 additions and 1270 deletions
|
|
@ -97,6 +97,9 @@ final class M365_Login_Certificate {
|
|||
return new WP_Error( 'key_bits', __( 'The RSA key must have at least 2048 bits.', 'm365-login' ) );
|
||||
}
|
||||
|
||||
if ( false !== strpos( $cert_pem, 'PRIVATE KEY' ) ) {
|
||||
return new WP_Error( 'cert_has_key', __( 'The certificate field contains a private key. Paste only the certificate (-----BEGIN CERTIFICATE-----) there.', 'm365-login' ) );
|
||||
}
|
||||
$cert = openssl_x509_read( $cert_pem );
|
||||
if ( false === $cert ) {
|
||||
return new WP_Error( 'cert_invalid', self::openssl_error( __( 'The certificate could not be read. Paste it in PEM format (-----BEGIN CERTIFICATE-----).', 'm365-login' ) ) );
|
||||
|
|
@ -110,9 +113,15 @@ final class M365_Login_Certificate {
|
|||
return new WP_Error( 'cert_expired', __( 'The certificate has already expired.', 'm365-login' ) );
|
||||
}
|
||||
|
||||
// Store exactly one clean certificate (drops chains, bundles and surrounding text).
|
||||
$clean = '';
|
||||
if ( ! openssl_x509_export( $cert, $clean ) || '' === $clean ) {
|
||||
return new WP_Error( 'cert_invalid', self::openssl_error( __( 'The certificate could not be read. Paste it in PEM format (-----BEGIN CERTIFICATE-----).', 'm365-login' ) ) );
|
||||
}
|
||||
|
||||
return array(
|
||||
'private_key' => $key_pem,
|
||||
'certificate' => $cert_pem,
|
||||
'certificate' => self::normalise_pem( $clean ),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue