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
|
|
@ -108,9 +108,10 @@ class M365_Login_Graph {
|
|||
* @param array|null $json JSON body for POST requests.
|
||||
* @param array $headers Extra headers.
|
||||
* @param bool $retry Retry on 429/503/504.
|
||||
* @param int $max_bytes Maximum response size (0 = unlimited).
|
||||
* @return array|WP_Error Response array from wp_remote_request().
|
||||
*/
|
||||
private function raw_request( $method, $path, $json = null, $headers = array(), $retry = true ) {
|
||||
private function raw_request( $method, $path, $json = null, $headers = array(), $retry = true, $max_bytes = 0 ) {
|
||||
$url = 0 === strpos( $path, self::GRAPH_BASE . '/' ) ? $path : self::GRAPH_BASE . $path;
|
||||
if ( 0 !== strpos( $url, self::GRAPH_BASE . '/' ) ) {
|
||||
return new WP_Error( 'graph_bad_url', 'Refusing to call a non-Graph URL.' );
|
||||
|
|
@ -137,6 +138,9 @@ class M365_Login_Graph {
|
|||
$args['headers']['Content-Type'] = 'application/json';
|
||||
$args['body'] = wp_json_encode( $json );
|
||||
}
|
||||
if ( $max_bytes > 0 ) {
|
||||
$args['limit_response_size'] = $max_bytes; // Stop downloading oversized bodies early.
|
||||
}
|
||||
|
||||
$response = wp_remote_request( $url, $args );
|
||||
if ( is_wp_error( $response ) ) {
|
||||
|
|
@ -368,7 +372,7 @@ class M365_Login_Graph {
|
|||
}
|
||||
$base = '/users/' . rawurlencode( strtolower( $oid ) );
|
||||
foreach ( array( $base . '/photos/240x240/$value', $base . '/photo/$value' ) as $path ) {
|
||||
$response = $this->raw_request( 'GET', $path, null, array( 'Accept' => 'image/*' ) );
|
||||
$response = $this->raw_request( 'GET', $path, null, array( 'Accept' => 'image/*' ), true, 2 * MB_IN_BYTES + 1 );
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue