A gallery metadata update can overwrite server files
CVE-2026-78088 affects the handler that updates page titles and Facebook sharing metadata in the Contest Gallery WordPress plugin. The handler accepts a file path from the request and rewrites that file without checking that it belongs to the gallery. An authenticated user with plugin backend access can therefore reach files outside the intended gallery directory, subject to the web-server account’s file permissions.
The declared affected range is Contest Gallery 32.0.1 and earlier; exploitation was demonstrated on 32.0.1. Version 33.0.0 is the reported fixed release, and its implementation changes how the destination file is selected.
Where the file boundary fails
The vulnerable logic is in 1_content-fb-like.php. Its legitimate purpose is to update a gallery page’s title and Open Graph metadata, the HTML fields that describe a page when it is shared on social platforms. Such an update should select an intended gallery file and safely insert the submitted text.
Instead, the handler takes fbcontent[<imageId>][baseUrlForFacebook] directly from POST input and uses it as a server-side filesystem path. Despite the field’s name, this value selects a local file. The handler checks file_exists(), which establishes only that the target exists. It does not establish that the target is an authorized gallery file or lies within the gallery directory.
The handler opens the target for reading and processes it line by line with fgets(). It replaces the entire first line containing <title> with a title element containing the attacker-controlled fbcontent[<imageId>][title], without sanitization or HTML escaping. Subsequent logic replaces an og:title line and unconditionally replaces the immediately following line with an og:description element containing submitted description text. That following line need not actually be a description element. The rewrite also replaces the first version=v2.8 string; other lines are preserved.
After constructing the replacement content, the handler opens the same supplied path with fopen(..., 'w') and writes the result with fwrite(). Opening an existing file in this mode truncates it before writing. The missing path restriction therefore turns a gallery metadata operation into an overwrite of an attacker-selected file.
“Arbitrary file overwrite” describes the destination choice, not unrestricted control over every byte. The target must already exist and be readable and writable by the web-server account. Controlled content insertion depends on matching title or Open Graph marker lines, and the replacement is limited to the portions the handler rewrites.
Who can reach the handler
The demonstrated route requires valid WordPress credentials and Contest Gallery backend access. In 32.0.1, the access checks allow administrator, editor, or author roles. Author access succeeded in testing; a subscriber received HTTP 403 with MISSINGRIGHTS. Contributor exclusion follows from the role checks and was not separately tested. The CVE record’s unauthenticated-upload wording and subscriber-access claim do not match this route, and no unauthenticated entry point was identified.
The request reaches the WordPress AJAX endpoint, /wp-admin/admin-ajax.php, through the post_contest_gallery_action_ajax action. The handler calls cg_require_backend_access() and validates two request-check values, cg_nonce and cgBackendHash. A nonce is a token used to help reject forged requests; the backend hash is checked against a value derived from the WordPress authentication salt. Users with plugin backend access can obtain both values from hidden fields on the backend page. Passing these checks does not validate the selected file or make the inserted content safe.
The request must also identify an existing gallery and select the edit-gallery branch. The gallery’s stored database version must satisfy dbVersion >= 10 for execution to reach the affected code. This is a per-gallery stored version check, distinct from the installed plugin release number.
When the overwrite becomes code execution
Remote code execution requires a further condition: the attacker must select a suitable PHP file with matching rewrite markers that the web server will execute through HTTP. If the inserted text contains valid PHP, a later request to that file can execute it under the web-server account. The demonstrated target was the WordPress core endpoint /wp-links-opml.php, and the subsequent GET request did not itself require authentication. Authentication is required for the preceding overwrite through the examined route.
Input handling also constrains the inserted code. WordPress applies wp_magic_quotes(), which escapes POST input. In the demonstrated execution path, injected content had to avoid quotes and backslashes because the added escaping could corrupt PHP syntax. The ability to overwrite a path alone therefore does not guarantee working code execution in every target file.
The demonstrated execution ran as www-data, the web-server account in that environment. Injected code could read and write files permitted to that account, and later HTTP requests could continue executing it while the modification persisted. Host or database privilege escalation was not demonstrated. Applicability with PHP’s opcode cache, OPcache, or read-only filesystems was not assessed. File corruption and site unavailability are possible consequences of the overwrite mechanism, but were not individually demonstrated.
How version 33.0.0 changes the operation
Upgrade Contest Gallery to version 33.0.0, the reported fixed release. Its implementation derives the output HTML path from wp_upload_dir(), the gallery identifier, and image-record data instead of accepting the destination from the POST field. It queries image records by GalleryID, checks the prefix of the resolved filesystem path using realpath(), and rejects slashes, backslashes, and null bytes in the image-name field, NamePic. These changes address the underlying failure by constraining the destination to files selected from gallery data.
The fixed implementation also applies sanitize_text_field(), esc_html(), and esc_attr() to clean submitted text and escape it for HTML text or attribute contexts. It adds an ABSPATH guard for WordPress context, checks that fbcontent is an array, and invokes cg_require_backend_access() within the affected file. The central corrections are destination-path control and safe content insertion; the authentication checks alone did not prevent the vulnerable overwrite.