FlawOpen

flawopen.com/Incidents/bricksforge-pro-forms-upload-metadata-october-2026

● Bricksforge WordPress plugin · CVE-2026-85097 · 2026-10-07 · CVSS 9.8 · Critical
FlawOpen Security Research

Bricksforge CVE-2026-85097: Pro Forms Upload Flaw

CVE-2026-85097 let unauthenticated requests exploit a mismatch between validated temporary file content and client-controlled destination metadata in Bricksforge Pro Forms. Patchstack reports exploitation attempts; update the plugin and investigate exposed sites.[1], [2], [3], [4], [5]

💡 Plain English Explainer (ELI5)

Imagine a mailroom checks that a parcel contains a harmless picture, then lets the sender replace the delivery label before sending it into an office that opens certain labels as programs. Bricksforge checked the temporary upload, but the later form submission could supply a different destination name. The defense is to keep the file identity and destination under server control from upload through storage.[3], [2]

Core Concepts & Subsystem Terms

Temporary upload
A file staged before a form submission completes. Validation at this stage does not make later client-supplied file metadata trustworthy.[2], [3]
CWE-434
Unrestricted Upload of File with Dangerous Type: a system accepts a file that can be interpreted or executed in a dangerous way.[1], [2]
Metadata trust boundary
The point where an application decides whether a filename, URL, MIME type, or path came from a trusted server record or an untrusted client.[2], [3]
CVE score and exploitation status
The Wordfence CNA/CVE record assigns CVSS 3.1 9.8 and its CISA enrichment says exploitation is none. Patchstack assigns 10.0 and reports telemetry first observed October 7, 2026. These are separately attributed records; neither establishes CISA KEV inclusion.[1], [2], [3], [4]
Illustrative code
The PHP comparison below models the validation boundary generically. It is not Bricksforge source code or a reconstruction of its patch; the vendor has not published those implementation details in the cited changelog.[2], [3], [5]

Framework mappings

  • CWE reference for the weakness described in this guide: CWE-434

Reported version status and operator action

Evidence sourceWhat it saysDefender action
Wordfence CNA / CVE recordDescribes unauthenticated arbitrary file upload; the recorded affected range ends at 3.1.8.9.Use this as the CNA-recorded scope, not proof that a deployed site is clean.
Patchstack (8 Oct 2026)Reports exploitation attempts first observed 7 Oct and identifies 3.1.8.10 as fixed.Treat this as Patchstack’s reported fix boundary; verify the resolved plugin version in each deployed site.
Bricksforge public changelogVersion 4.0.1 lists a Pro Forms upload security fix but does not identify the 3.1.8.10 boundary.Do not infer from the changelog alone that 4.0.1 is the first fixed version or that a particular 3.x build is safe.
Exposed or suspected-compromise siteThe sources describe exploitation attempts, not proof that every targeted site was compromised.Update to a currently vendor-supported release; review upload and web-server logs and investigate unexpected files before declaring recovery.

Incident Timeline

2026-10-07

Wordfence lists the advisory's public publication date as October 7. Patchstack says its telemetry first observed attempts that day at 21:47 UTC; advisory publication and telemetry observation are separate events.[2], [3]

2026-10-08

The CVE record lists datePublished as October 8, one day after the Wordfence advisory's October 7 public date. Patchstack's campaign report also says it was published October 8; these dates describe separate records and publications.[1], [2], [3]

2026-10-08

Patchstack's October 8 analysis describes the validation mismatch and reported attempts, and identifies 3.1.8.10 as patched. Bricksforge's changelog separately lists a Pro Forms upload security fix in 4.0.1 but does not establish the exact 3.x fixed boundary.[3], [4], [5]

Step-by-Step Attack Flow

Step 1

A temporary file passes an initial check

The CNA describes a prior temporary upload that passes MIME validation. Passing this check does not authorize arbitrary later changes to the file's name or destination.[2], [1]

Step 2

Form submission supplies separate metadata

Patchstack reports that later form processing trusted client-supplied temporaryFileUploads metadata, including a URL that could disagree with the already validated file. The flaw is the trust split between checked content and unchecked destination metadata.[2], [3]

Step 3

The file is placed under a dangerous name

When the server uses that client-controlled destination to finalize the upload, a dangerous extension can cause server-side interpretation if the destination is executable. This describes the failure at a high level; no request format or payload is needed to understand it.[2], [3]

Step 4

Exposure can become server compromise

The CNA says the issue can allow arbitrary PHP execution. Patchstack reports exploitation attempts and advises updating. Its observations do not prove every targeted site was compromised or establish a threat-actor identity.[2], [3]

Source Code: Flaw vs. Secure Implementation

This generic example demonstrates server-owned upload identity, per-user lookup, content-type rechecking, generated filenames, and private storage. It is not Bricksforge's code or its actual patch. Production code must also enforce size limits, safe storage permissions, atomic state transitions, and context-appropriate serving; the direct fix for affected sites is to update Bricksforge to a vendor-supported fixed release.[2], [3]

UNPATCHED FLAW
function finalize_upload( array $item, string $stagedPath, string $uploadDir ): string {
    // Client metadata chooses the final name after an earlier MIME check.
    $name = basename( (string) parse_url( $item['file']['url'], PHP_URL_PATH ) );
    $destination = $uploadDir . DIRECTORY_SEPARATOR . $name;
    if ( ! rename( $stagedPath, $destination ) ) {
        throw new RuntimeException( 'Could not finalize upload' );
    }
    return $destination;
}
HARDENED SECURE PATCH
function finalize_upload( string $uploadId, UploadRegistry $registry, string $privateDir ): string {
    // Resolve ownership and path from a server-side record, never a client URL.
    $upload = $registry->findPendingForCurrentUser( $uploadId );
    if ( $upload === null || ! is_file( $upload->path ) ) {
        throw new RuntimeException( 'Unknown pending upload' );
    }
    $types = [ 'image/jpeg' => 'jpg', 'image/png' => 'png' ];
    $mime = ( new finfo( FILEINFO_MIME_TYPE ) )->file( $upload->path );
    if ( ! isset( $types[ $mime ] ) ) {
        throw new RuntimeException( 'Unsupported file type' );
    }
    $destination = $privateDir . DIRECTORY_SEPARATOR . bin2hex( random_bytes( 16 ) ) . '.' . $types[ $mime ];
    if ( ! rename( $upload->path, $destination ) ) {
        throw new RuntimeException( 'Could not finalize upload' );
    }
    $registry->markConsumed( $uploadId );
    return $destination;
}

Engineering & System Hardening Checklist

Sources