WordPress + Microsoft Office 365 / Azure AD | LOGIN Persistent Cross-Site Scripting (CVE-2021-43409)

The AppCheck Research team identified a security flaw within the “WPO365 | LOGIN” WordPress plugin. The plugin has been downloaded 88,664 times at the time of writing. This blog post details the finding along with remediation advice.


The “WPO365 | LOGIN” WordPress plugin (up to and including version 15.3) by wpo365.com is vulnerable to a persistent Cross-Site Scripting (XSS) vulnerability (also known as Stored or Second-Order XSS).

Persistent XSS vulnerabilities occur when the application stores and retrieves client supplied data without proper handling of dangerous content. This type of XSS vulnerability is exploited by submitting malicious script content to the application which is then retrieved and executed by other application users.

The attacker could exploit this to conduct a range of attacks against users of the affected application such as session hijacking, account take over and accessing sensitive data.

In this case, the XSS payload can be submitted by any anonymous user, the payload then renders and executes when a WordPress administrator authenticates and accesses the WordPress Dashboard. The injected payload can carry out actions on behalf of the administrator including adding other administrative users and changing application settings. This flaw could be exploited to ultimately provide full control of the affected system to the attacker.

You can read more about XSS here:


Technical Analysis

The vulnerability occurs when rendering error OpenID authentication error messages within the WPO365 dashboard. The affected code path can be found in “ServicesRouter_Service.php”

The routing component first checks that the “error” POST parameter is set before calling the “route_openidconnect_error” function (line 52):

// process openid connect error

if ( isset( $_POST[ 'error' ] ) ) {

add_action( 'init', 'WpoServicesRouter_Service::route_openidconnect_error' );

return true;



The “route_openidconnect_error” method is then called which reads the “error_description” POST parameter before writing it to the internal log service without sanitisation (line 195).

public static function route_openidconnect_error() {

$error_string = $_POST[ 'error' ] . isset( $_POST[ 'error_description' ] ) ? $_POST[ 'error_description' ] : '';

Log_Service::write_log( 'ERROR', __METHOD__ . ' -> ' . $error_string );

Authentication_Service::goodbye( Error_Service::CHECK_LOG );



The following HTTP request can be sent to the target application to trigger the vulnerability:

POST / HTTP/1.1 Host: Cookie: wordpress_test_cookie=WP%20Cookie%20check Content-Length: 242 Content-Type: application/x-www-form-urlencoded error=2&error_description=<img+src=a+onerror=alert(%26quot;XSS_Proof_of_Concept!%26quot;)



Accessing the WPO365 login page will then render the injected payload, in this case: alert(“XSS_Proof_of_Concept!”)



The vendor released a security update on the same day the issue was reported to them by AppCheck. This is an incredible turnaround and AppCheck would like to thank wpo365.com and Marco van Wieren for their rapid response in resolving this issue.

Further information can be found here:

Change Log

WordPress + Microsoft Office 365 / Azure AD | LOGIN

Disclosure Timeline:

29th September 2021:     

Reported to vendor

29th September 2021: 

Vendor remediated the flaw and published a fix.

13th October 2021:

AppCheck advisory published.

Get started with Appcheck

No software to download or install.

Contact us or call us 0113 887 8380

Start your free trial

Your details
IP Addresses

Get in touch

Please enable JavaScript in your browser to complete this form.