Skip to content

Instantly share code, notes, and snippets.

@bonny
Last active January 17, 2026 13:51
Show Gist options
  • Select an option

  • Save bonny/dceab0c8582f08075919e9f760380f50 to your computer and use it in GitHub Desktop.

Select an option

Save bonny/dceab0c8582f08075919e9f760380f50 to your computer and use it in GitHub Desktop.
WordPress.org Plugin Update API response with autoupdate=1 (forced security update) - Real example from WooCommerce 10.4.2→10.4.3

WordPress.org Plugin Update API - The autoupdate Field for Forced Security Updates

This research was conducted for Simple History, a WordPress activity log plugin. We wanted to understand exactly how WordPress handles forced security updates so we could display this information clearly to site administrators. This document shares our findings.


API endpoint: POST https://api.wordpress.org/plugins/update-check/1.1/ Date captured: January 14, 2026 Plugin: WooCommerce 10.4.2 → 10.4.3

Why This Matters

In late December 2025, a security vulnerability (CVE-2025-15033) was discovered in WooCommerce's Store API. The WooCommerce team worked with the WordPress.org security team to push version 10.4.3 as a forced automatic update to all affected sites—regardless of individual auto-update settings.

For site owners, this meant WooCommerce updated overnight without any action on their part. Without an activity log, you might not even notice it happened—or worse, notice but not understand why.

Forced updates regularly confuse site administrators. When a plugin updates despite auto-updates being disabled, the natural assumption is that something is broken. WordPress.org support forums see posts like this one after every forced security update, with users wondering why their settings were ignored.

Vulnerability details:

  • CVE: CVE-2025-15033
  • Severity: 6.5 (Medium) - Sensitive Data Exposure
  • Affected versions: WooCommerce 8.1 to 10.4.2
  • Fixed in: WooCommerce 10.4.3

References:

How Simple History Detects Forced Updates

Based on this research, Simple History now distinguishes between forced security updates and regular auto-updates. When a plugin is updated via WordPress.org's security override, you'll see exactly why it happened:

Simple History showing a forced security update with update method and upgrade notice

The log shows:

  • Update method: "Security auto-update" for forced updates
  • Update notice: The message from WordPress.org explaining why the update was pushed

The autoupdate Field

The autoupdate field in the API response is the critical indicator:

  • When true: WordPress will auto-update this plugin regardless of user settings
  • When absent: Normal update behavior (respects user's auto-update preferences)

This flag is manually set by the WordPress.org security team for critical security vulnerabilities. Most plugins will never have this field.

upgrade_notice

The upgrade_notice field contains a human-readable message explaining why this update is important. This field does NOT force updates—only autoupdate does that.

Real API Examples

You can query the WordPress.org plugin update API directly with curl to see the autoupdate flag.

Forced Security Update (WooCommerce)

curl -s -X POST 'https://api.wordpress.org/plugins/update-check/1.1/' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'plugins={"plugins":{"woocommerce/woocommerce.php":{"Version":"10.4.2"}}}' \
  | jq

Response (note autoupdate and upgrade_notice fields):

{
  "plugins": {
    "woocommerce/woocommerce.php": {
      "id": "w.org/plugins/woocommerce",
      "slug": "woocommerce",
      "plugin": "woocommerce/woocommerce.php",
      "new_version": "10.4.3",
      "url": "https://wordpress.org/plugins/woocommerce/",
      "package": "https://downloads.w.org/plugin/woocommerce.10.4.3.zip",
      "icons": {
        "1x": "https://ps.w.org/woocommerce/assets/icon.svg?rev=3234504",
        "svg": "https://ps.w.org/woocommerce/assets/icon.svg?rev=3234504"
      },
      "banners": {
        "2x": "https://ps.w.org/woocommerce/assets/banner-1544x500.png?rev=3234504",
        "1x": "https://ps.w.org/woocommerce/assets/banner-772x250.png?rev=3234504"
      },
      "banners_rtl": [],
      "requires": false,
      "tested": "6.9",
      "requires_php": false,
      "requires_plugins": [],
      "compatibility": [],
      "autoupdate": true,
      "upgrade_notice": "Version 10.4.3 contains security fixes and is highly recommended for all users."
    }
  },
  "translations": []
}

Normal Update (Simple History)

Compare with a normal plugin update response—no autoupdate or upgrade_notice fields:

curl -s -X POST 'https://api.wordpress.org/plugins/update-check/1.1/' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'plugins={"plugins":{"simple-history/index.php":{"Version":"5.21.0"}}}' \
  | jq
{
  "plugins": {
    "simple-history/index.php": {
      "id": "w.org/plugins/simple-history",
      "slug": "simple-history",
      "plugin": "simple-history/index.php",
      "new_version": "5.22.0",
      "url": "https://wordpress.org/plugins/simple-history/",
      "package": "https://downloads.wordpress.org/plugin/simple-history.5.22.0.zip",
      "icons": {
        "1x": "https://ps.w.org/simple-history/assets/icon.svg?rev=3225008",
        "svg": "https://ps.w.org/simple-history/assets/icon.svg?rev=3225008"
      },
      "banners": {
        "2x": "https://ps.w.org/simple-history/assets/banner-1544x500.png?rev=3225008",
        "1x": "https://ps.w.org/simple-history/assets/banner-772x250.png?rev=3225008"
      },
      "banners_rtl": [],
      "requires": "6.3",
      "tested": "6.9",
      "requires_php": "7.4",
      "requires_plugins": [],
      "compatibility": []
    }
  },
  "translations": []
}

How WordPress Core Handles This

From wp_update_plugins() and class-wp-automatic-updater.php:

// First check: API-forced update (security team override)
$update = ! empty( $item->autoupdate );

// Second check: User-enabled auto-update (only if not already forced)
if ( ! $update && wp_is_auto_update_enabled_for_type( $type ) ) {
    $auto_updates = (array) get_site_option( "auto_update_{$type}s", array() );
    $update = in_array( $item->{$type}, $auto_updates, true );
}

Detection in PHP

To detect if an update was forced vs user-enabled:

$update_plugins = get_site_transient( 'update_plugins' );
$auto_updates = get_site_option( 'auto_update_plugins', array() );

$plugin_file = 'woocommerce/woocommerce.php';
$plugin_info = $update_plugins->response[ $plugin_file ] ?? null;

if ( $plugin_info ) {
    $api_forced = ! empty( $plugin_info->autoupdate );
    $user_enabled = in_array( $plugin_file, $auto_updates, true );
    $upgrade_notice = $plugin_info->upgrade_notice ?? '';

    if ( $api_forced && ! $user_enabled ) {
        // FORCED SECURITY UPDATE: WordPress.org override
    } elseif ( $user_enabled ) {
        // USER-ENABLED: User explicitly enabled auto-updates
    } else {
        // MANUAL: User clicked update button
    }
}

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment