WP Manifestindependent plugin directory
manifest / media / just-gcs-offload

Just GCS Offload WP Registry grade B. Medium-severity findings · 1 findingWP RegistryMedium-severity findings · 1 findingOpen the reportB

A lightweight, dependency-free WordPress plugin to offload Media Library to Google Cloud Storage (GCS). / 輕量、無依賴的 WordPress GCS 媒體庫儲存空間卸載外掛。

★ 3stars
9release downloads
v1.5.1latest · 2mo ago

Install

Download just-gcs-offload-v1.5.1.zip From the v1.5.1 release on GitHub, Aug 20, 2026

Upload it under Plugins → Add New Plugin → Upload Plugin, then activate.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/ivanusto/just-gcs-offload/releases/download/v1.5.1/just-gcs-offload-v1.5.1.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

繁體中文版說明請參見 README.zh-TW.md | WordPress on GCS Implementation Guide | WordPress on GCS 中文實作指南

A lightweight, dependency-free WordPress plugin to offload your Media Library to a Google Cloud Storage (GCS) bucket.

[!NOTE] Looking for Amazon S3 or S3-compatible (R2, B2, Spaces, MinIO) storage support instead? Check out our sister project: Just S3 Offload.

Unlike other bloated cloud storage plugins, Just GCS Offload is designed to be as small and efficient as possible. It implements a lightweight GCS REST client in pure PHP using cURL and native OpenSSL JWT signing for Service Account authentication, completely bypassing the massive official Google Cloud SDK.

Features

  • Zero External Dependencies: Weighs only a few dozen kilobytes. No bulky vendor/ folder or external libraries.
  • Service Account JWT Authentication: Authenticates securely using a Google Service Account JSON key, utilizing native OpenSSL (openssl_sign) for RS256 signing.
  • Automatic Media Offloading: Automatically uploads new images and all generated sub-sizes (thumbnails) to GCS during upload.
  • URL & Srcset Rewriting: Seamlessly rewrites image URLs and responsive srcset paths to point to GCS or a custom CDN domain.
  • Optional Local Cleanup: Optionally deletes the local server copy of uploaded files to save disk space.
  • Automatic Deletion: Automatically deletes original and resized files from GCS when an attachment is permanently deleted from the WordPress admin.
  • WP-CLI Integration: Provides powerful command-line tools to migrate existing media library items and sync database metadata.
  • Connection Test: A simple button in settings to test read/write/delete permissions.

Requirements

  • PHP 7.4 or higher
  • PHP OpenSSL extension enabled (for JWT signing)
  • WordPress 6.0 or higher

Installation

  1. Download the latest just-gcs-offload.zip from the Releases page.
  2. In your WordPress admin, go to Plugins -> Add New -> Upload Plugin, select the zip file, and click Install Now.
  3. Activate the plugin.

GCS Bucket Configuration

To ensure your offloaded images are publicly readable, configure your GCS bucket using one of the following methods:

Method A: Uniform Bucket-Level Access (Recommended)

  1. Enable Uniform bucket-level access in your bucket's permissions.
  2. Grant the Storage Object Viewer (roles/storage.objectViewer) IAM role to the principal allUsers.
  3. In WordPress settings, keep the "Set Public ACL" option disabled.

Method B: Fine-grained Access Control

  1. Enable Fine-grained access control in your bucket.
  2. In WordPress settings, enable the "Set Public ACL" option. This will apply a publicRead ACL to every uploaded object.

Configuration Settings

Navigate to Settings -> GCS Offload in your WordPress dashboard to configure the following settings:

  • Service Account JSON Key: Paste the complete contents of your Service Account private key JSON file. The Service Account must have permissions to create and delete GCS objects.
  • GCS Bucket Name: Enter the target GCS bucket name (e.g., my-wordpress-bucket).
  • Folder Path Prefix: (Optional) Subfolder path inside the bucket (e.g., wp-content/uploads). Do not add leading or trailing slashes.
  • Custom Domain / CDN URL: (Optional) Custom domain or CDN mapping (e.g., https://cdn.example.com). If empty, the default GCS URL will be used: https://storage.googleapis.com/{bucket}.
  • Cache-Control Header: The Cache-Control header applied to uploaded objects (defaults to public, max-age=31536000).
  • Set Public ACL: Check this if using Fine-grained access control on your bucket.
  • Delete Local Files: Check this to delete local copies of files after uploading them to GCS. When a local file is needed again, the plugin downloads it back from GCS on demand, so the built-in image editor (crop/rotate) keeps working. Note that the Bulk Upload tool and wp gcs-offload sync-all --delete-local each carry their own delete-local switch, independent of this setting.

Click Run Connection Test to verify that your credentials and permissions are configured correctly.

Filters

  • just_wp_gcs_skip_attachment( bool $skip, int $attachment_id ) - exclude an attachment from being offloaded. The site icon is skipped by default.

  • just_wp_gcs_companion_meta_keys( string[] $keys ) - the attachment metadata keys treated as companion files sitting next to the main file. Defaults to original_image, source_image, animated_video and animated_video_poster.

  • just_wp_gcs_rehydrate( bool $allow, int $attachment_id ) - allow a missing local file to be downloaded back from GCS for the current request.

    Rehydration is deliberately restricted, because get_attached_file also fires on read-only paths. wp_prepare_attachment_for_js() in particular runs once per attachment whenever the Media Library grid or the block editor media picker loads a page of results, so downloading there would turn one screen into dozens of full-size bucket requests. By default only WP-CLI and the built-in image editor are allowed. Tools that genuinely need the local original can opt in:

    add_filter( 'just_wp_gcs_rehydrate', function ( $allow ) {
        return defined( 'MY_REGENERATING_THUMBNAILS' ) ? true : $allow;
    } );

WP-CLI Commands

For developers and system administrators, the plugin provides custom WP-CLI commands to perform batch operations and migrations.

1. Sync Database Metadata

If you have already copied your files to the GCS bucket using tools like gsutil or rclone, use this command to generate the offload metadata (_wp_gcs_info) in the database so WordPress rewrites the URLs.

wp gcs-offload sync-metadata [--bucket=<bucket>] [--prefix=<prefix>] [--overwrite]

2. Batch Upload Local Files

Scan all existing media library attachments, upload them to GCS, and update their database records.

wp gcs-offload sync-all [--delete-local] [--overwrite]
  • Use --delete-local to remove local copies after successful upload.
  • Use --overwrite to re-upload files that are already marked as synced.

Troubleshooting

If you encounter any issues (such as a fatal error or blank screen in the Media Library):

  1. Enable debugging in your wp-config.php:
    define( 'WP_DEBUG', true );
    define( 'WP_DEBUG_LOG', true );
    define( 'WP_DEBUG_DISPLAY', false );
  2. Re-trigger the error.
  3. Check the logs:
    • WordPress Debug Log: wp-content/debug.log
    • Web Server Error Logs: /var/log/apache2/error.log or /var/log/nginx/error.log

License / 授權條款

This project is licensed under the GNU General Public License v2.0 or later (GPL-2.0-or-later).

Releases

3 releases. Each count is every asset in that release; expand a row for the breakdown.

Tag
Published
Assets
Downloads
v1.5.1 latest
Aug 20, 2026 2mo ago
just-gcs-offload-v1.5.1.zip
5
Aug 20, 2026 2mo ago
just-gcs-offload-v1.5.0.zip
2
Aug 18, 2026 2mo ago
just-gcs-offload-v1.4.0.zip
2
B grade

Security

Just GCS Offload 1.5.1 · audited by WP Registry

Medium-severity findings.

1 medium
Audited release
1.5.1
Findings
1
Worst severity
medium
Content hash
58d1999e971ff64ea2baf202…

Findings

  • medium Spoofable image-editor action allows unauthenticated GCS rehydration

    missing_capability

    Just_WP_GCS_Media_Handler::should_rehydrate() decides whether a missing local attachment may be downloaded from GCS solely by checking $_REQUEST['action'] against image-editor, imgedit-preview, and crop-image (or WP-CLI). There is no is_admin(), current_user_can(), or nonce check; the inline comment assumes core will have authorized those actions, but the gate runs on the global get_attached_file filter for every caller. Core image_downsize() calls wp_attachment_is_image() → get_attached_file() before apply_filters('image_downsize'), so the plugin's gcs_image_downsize short-circuit never prevents the hook from firing on front-end image rendering. An unauthenticated visitor can therefore append ?action=image-editor to any public URL that loads offloaded media (home/posts with featured images or image blocks, attachment permalinks via prepend_attachment → wp_attachment_is, or GET /wp-json/wp/v2/media?action=image-editor whose view-context filename/filesize fields also call get_attached_file). When local files were removed after offload, maybe_rehydrate_local_file() uses the stored Service Account token to stream each original from the bucket onto disk. Impact is unauthorized use of GCS credentials: egress billing, disk fill, and request-time DoS, not arbitrary-path RCE (the destination is the path WordPress already computed for that attachment). Requires offload metadata plus a missing local file (the Delete Local Files setting, bulk/CLI delete-local, or equivalent).

    includes/class-gcs-media-handler.php:230-307

    Recommendation

    Do not treat $_REQUEST['action'] as authorization. Allow rehydration only in WP-CLI or when is_admin()/wp_doing_ajax() is true and the current user can edit the attachment (current_user_can('edit_post', $attachment_id) or upload_files), ideally after the core image-editor nonce (image_editor-{$id}) succeeds. Reject the three action names on front-end and unauthenticated REST requests.

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.