Greetings.
Probing one of our websites, running Newspaper 12.2 with WordPress 6.1.1, we have found that there is a security vulnerability on category pages that use infinite loading.
This option:
Theme Panel > Categories > Category global settings > Pagination style > Infinite loading
When this infinite loading is active Newspaper does a POST request to wp-admin/admin-ajax.php with a loopState action to retrieve more posts, and the response is not properly escaped leading to an opening that can allow a reflected cross-site scripting attack.
Here’s an example on your own demo site:
The request:
curl 'https://demo.tagdiv.com/newspaper_pro/wp-admin/admin-ajax.php?td_theme_name=Newspaper&v=12.2' \
-H 'content-type: application/x-www-form-urlencoded; charset=UTF-8' \
-H 'x-requested-with: XMLHttpRequest' \
--data-raw 'action=td_ajax_loop&loopState%5BsidebarPosition%5D=no_sidebar&loopState%5BmoduleId%5D=17&loopState%5BcurrentPage%5D=2&loopState%5Bmax_num_pages%5D=2&loopState%5Batts%5D%5Bcategory_id%5D=1&loopState%5Batts%5D%5Boffset%5D=3&loopState%5Bajax_pagination_infinite_stop%5D=%3Cimg+src%3DBOGUS%3E&loopState%5Bserver_reply_html_data%5D='
The (truncated) response:
HTTP/1.1 200 OK
...
Content-Type: text/html; charset=UTF-8
...
{
"sidebarPosition":"no_sidebar",
"moduleId":"17",
"currentPage":"2",
"max_num_pages":"2",
"atts": {
"category_id":"1",
"offset":"3"
},
"ajax_pagination_infinite_stop":"",
"server_reply_html_data":""
}
Notice how parameters sent for the loopState action via ajax are reflected back to the client unescaped. In this example, the parameter ajax_pagination_infinite_stop was altered to include a bogus image tag instead of a number. Because HTML tags are not being properly escaped when the response JSON is encoded, and combined with the fact that the Content-Type of the response is text/html, this results in the malformed request being reflected towards the client and rendered as HTML, which can be abused by a malicious actor.
A possible solution:
On your td-composer plugin, the function on_ajax_loop of the class td_ajax deals with loopState requests. Currently it returns with the following statement:
die(json_encode($loopState));
Supplying the flag JSON_HEX_TAG to encode the symbols for opening and closing HTML tags seems to mitigate the issue:
die(json_encode($loopState, JSON_HEX_TAG));
Best regards.