Fix the findings of the third security audit
- Privileged accounts: the UPN rule also applies when bind_oid is off or the account is not bound; privileges are checked on every site of a multisite user, include code/HTML capabilities (unfiltered_html, plugins, themes, users) and the remembered roles of deactivated accounts. - send_auth_cookies protection also works on WordPress 6.0/6.1. - Run lock via INSERT IGNORE (atomic), refreshed during long runs; a shutdown handler reports fatal errors and frees the lock. - Deprovisioning only for accounts linked in the current tenant (tenant recorded per account; legacy links not found are left alone). - Safety stop based on the accounts linked before the run; new safety stop for removals of administrative roles. - Disable is idempotent; row-action nonces are bound to the state. - Profile photos are re-encoded to 240 px (drops EXIF and appended data), size-limited while downloading, removed on deactivation; index.php guard in the photo folder. - Privacy exporter and eraser for the copied data. - One-time migration hardens accounts deactivated by 1.0 and cleans a stored certificate bundle; the .cer download is always re-exported. - Password fields hidden in button-only mode even when the connection is broken; settings written non-autoloaded; robust user ID queries. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b35f6a867b
commit
9b893e42bc
9 changed files with 582 additions and 104 deletions
|
|
@ -232,6 +232,22 @@ class M365_Login_Settings {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the stored certificate by a clean re-export (drops key bundles or chains saved by older versions).
|
||||
*/
|
||||
public function normalise_stored_certificate() {
|
||||
$pem = $this->certificate_pem();
|
||||
if ( '' === $pem ) {
|
||||
return;
|
||||
}
|
||||
$clean = M365_Login_Certificate::clean_pem( $pem );
|
||||
if ( '' !== $clean && $clean !== $pem ) {
|
||||
$all = $this->all();
|
||||
$all['cert_certificate'] = $clean;
|
||||
$this->write( $all );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the stored certificate and key.
|
||||
*/
|
||||
|
|
@ -252,7 +268,7 @@ class M365_Login_Settings {
|
|||
*/
|
||||
private function write( $all ) {
|
||||
$this->raw_write = true;
|
||||
update_option( M365_LOGIN_OPTION, $all );
|
||||
update_option( M365_LOGIN_OPTION, $all, false ); // Holds encrypted secrets: never autoloaded.
|
||||
$this->raw_write = false;
|
||||
$this->cache = null;
|
||||
}
|
||||
|
|
@ -655,7 +671,7 @@ class M365_Login_Settings {
|
|||
if ( '' === $map_role || ! get_role( $map_role ) ) {
|
||||
continue;
|
||||
}
|
||||
$name = isset( $row['name'] ) ? sanitize_text_field( wp_unslash( (string) $row['name'] ) ) : '';
|
||||
$name = isset( $row['name'] ) && is_scalar( $row['name'] ) ? sanitize_text_field( wp_unslash( (string) $row['name'] ) ) : '';
|
||||
$map[ $id ] = array(
|
||||
'name' => '' === $name ? $id : mb_substr( $name, 0, 120 ),
|
||||
'role' => $map_role,
|
||||
|
|
@ -671,6 +687,9 @@ class M365_Login_Settings {
|
|||
if ( ! empty( $input['sync_attributes'] ) && is_array( $input['sync_attributes'] ) ) {
|
||||
$known = array_keys( M365_Login_Sync::attributes() );
|
||||
foreach ( $input['sync_attributes'] as $attribute ) {
|
||||
if ( ! is_scalar( $attribute ) ) {
|
||||
continue;
|
||||
}
|
||||
$attribute = sanitize_text_field( wp_unslash( (string) $attribute ) );
|
||||
if ( in_array( $attribute, $known, true ) ) {
|
||||
$attributes[] = $attribute;
|
||||
|
|
@ -722,7 +741,7 @@ class M365_Login_Settings {
|
|||
if ( ! self::is_guid( $id ) ) {
|
||||
continue;
|
||||
}
|
||||
$name = sanitize_text_field( wp_unslash( (string) $name ) );
|
||||
$name = is_scalar( $name ) ? sanitize_text_field( wp_unslash( (string) $name ) ) : '';
|
||||
$groups[ $id ] = '' === $name ? $id : mb_substr( $name, 0, 120 );
|
||||
if ( count( $groups ) >= 100 ) {
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue