Two-Factor includes a nonce during the validate_2fa callback, and while the fields are present in the POST request for the revalidate endpoint, it's not used.
Props @xknown for the report.
Why?
A nonce should be present on all POST requests that perform actions, to prevent potential CSRF attacks.
How?
Due to the revalidation occurring with an authenticated session, wp_create_nonce() is used to validate the request. The Two-Factor login_nonce functionality is not used, to ensure that the revalidate nonce can't be used to login a new session.
The nonce is ignored during GET requests for the revalidate endpoint.
The initial load of the revalidate screen can be sans-nonce, this is not a concern IMHO.
The change-provider link DOES include a nonce, but it is not validated. This is due to code-reuse between the validate_2fa and revalidate_2fa actions. The inclusion of the nonce here that is not validated is not a risk, due to it being a GET request and not performing an action.
The check could be changed to if ( ( $is_post_request || $nonce ) && ! wp_verify_nonce( $nonce .. ) ) { if required, but it seems more explicit to only require it for POST requests, as that's where it's actually protecting against an attack.
Testing Instructions
Apply PR
Login as normal.
During revalidate, remove the wp-auth-nonce from the POST payload, ensure the request fails.
Ensure revalidate succeeds with the wp-auth-nonce field.
What?
Two-Factor includes a nonce during the validate_2fa callback, and while the fields are present in the POST request for the revalidate endpoint, it's not used.
Props @xknown for the report.
Why?
A nonce should be present on all POST requests that perform actions, to prevent potential CSRF attacks.
How?
Due to the revalidation occurring with an authenticated session,
wp_create_nonce()
is used to validate the request. The Two-Factor login_nonce functionality is not used, to ensure that the revalidate nonce can't be used to login a new session.The nonce is ignored during GET requests for the revalidate endpoint.
The check could be changed to
if ( ( $is_post_request || $nonce ) && ! wp_verify_nonce( $nonce .. ) ) {
if required, but it seems more explicit to only require it for POST requests, as that's where it's actually protecting against an attack.Testing Instructions
wp-auth-nonce
from the POST payload, ensure the request fails.wp-auth-nonce
field.Screenshots or screencast
Changelog Entry
N/A - Unreleased feature.