Coordinated disclosureCVE-2026-15054WordPress · PHPWPScan · 3.7 Low

Proof/CVE-2026-15054

CS.08 — Published CVE

The form was never published. It answered anyway.

Bit Form checked whether a form was active when it decided to render it — but not when it decided to process a submission. An unauthenticated attacker could ask the AJAX layer for a valid token set on an inactive form and post to it, creating an entry and firing every attached workflow, email notifications included.

CVECVE-2026-15054
Componentbit-form · PHP
Affected< 3.1.2
Fixed3.1.2
WeaknessCWE-862
WPScan CVSS3.7 Low
ReporterCharles Vosburgh
An unauthenticated request obtained submission tokens for an inactive form, posted to it, and triggered the form's workflows — including outbound email — on a form the site had never published.
Weakness
CWE-862
Trigger
bitforms_submit_form
Control
Render gate present
Outcome
Entry + workflow on inactive form
Public-safety boundary. This page explains the authorization gap, the validation method and the remediation boundary. It describes the token flow at a level sufficient to understand and fix the issue, not to weaponize it. Version 3.1.2 fixes the issue.

An inactive or unpublished form is a form the site has deliberately withheld — a draft, a seasonal promotion, a workflow still under construction. The active-state check is the authorization decision that keeps such a form from doing work. If that check runs only when rendering, but not when accepting input, the form is effectively live to anyone who can reach the endpoint directly.

An inactive form must not accept submissions or fire its workflows, regardless of how a request reaches the submission endpoint.

The bug was not that Bit Form issued submission tokens. The bug was that the active-state gate governed the front-end render path while the AJAX token and submit actions treated every form — active or not — as fair game.

Only published forms appear on the site, so a page visitor can only submit forms that are active. That front-end assumption was allowed to stand in for an authorization check at the endpoint. The AJAX actions that mint tokens and accept submissions never asked whether the form was active before doing their work.

Condensed submission pathAJAX token → submit → workflow
bitforms_onload_added_field_and_property (nopriv):
  load form by id
  issue CSRF + identity tokens        // no is_active(form) check

bitforms_submit_form (nopriv):
  verify tokens
  create entry
  run workflows / notifications        // no is_active(form) check

// with WP-Cron disabled:
cronNotOk token -> execute workflows explicitly

// missing at every endpoint: if (!form.active) return 403;

Because the token-issuing action and the submit action are both registered for unauthenticated (nopriv) access, an attacker never needs the rendered page. They request tokens for an inactive form by ID, then submit against them — the entry is written and the attached workflows run.

01 · Token

Onload action

Unauthenticated request yields CSRF + identity tokens for an inactive form.

02 · Submit

Submit action

Tokens are accepted; an entry is created for the inactive form.

03 · Workflow

Notifications

Attached workflows execute, including outbound email.

04 · Replay

cronNotOk

With WP-Cron off, a replayed token forces explicit workflow execution.

1

Target an inactive form by ID

The attacker identifies a form the site has not published — a draft or disabled form whose ID is guessable or enumerable — and never loads a public page for it.

2

Acquire tokens unauthenticated

A request to the bitforms_onload_added_field_and_property action returns the CSRF and identity tokens the submit endpoint expects, even for the inactive form.

3

Submit to the inactive form

Using those tokens, the attacker posts to bitforms_submit_form. An entry is created and the form's workflows execute — email notifications included.

4

Force workflows where cron is off

On installs with WP-Cron disabled, the attacker replays a cronNotOk token to explicitly trigger workflow execution rather than waiting on a scheduler.

5

Effect without publication

Draft-form entries accumulate and outbound notifications fire from a form the operator believed was inert — usable for spam relay, data seeding, or probing unfinished workflows.

The finding was promoted only after the vulnerable path, the expected-behavior control and the fixed control were retained together.

Expected path

Active form

An active form accepts a submission and runs its workflow — the intended behavior.

Vulnerable path

Inactive form

The same unauthenticated flow against an inactive form still creates an entry and fires notifications.

Fixed control

3.1.2 endpoints

Token, submit and cron endpoints return HTTP 403 "Form is not active" for inactive forms.

SETUP form marked inactive / unpublished TOKEN nopriv onload action returned CSRF + identity tokens SUBMIT bitforms_submit_form accepted entry on inactive form WORKFLOW notification email dispatched INACTIVE-FORM submission + workflow: CONFIRMED MARKER=BITFORM_INACTIVE_SUBMIT

Not rendering a form is a UI decision. Refusing to process it is an authorization decision. The two were conflated: the site's front end hid inactive forms, and that concealment was treated as though it enforced access.

The durable engineering rule is that state which governs whether an action is permitted must be re-checked at every endpoint that performs the action — especially unauthenticated AJAX handlers, which never see the front-end gate at all.

The SecHive research loop

Agents found the missing check. Evidence proved the workflow actually fired.

The workflow did not stop at "the submit handler lacks an active check." Each stage had to produce evidence, or a refutation, before the candidate could move forward.

SK.01

Source mapping

Trace the nopriv token and submit actions and locate every place the form's active state is (and is not) consulted.

SK.02

Authorization hypothesis

Challenge the assumption that hiding inactive forms on the front end prevents submissions to them.

SK.03

Runtime construction

Drive the token → submit → workflow flow directly against an inactive form, unauthenticated, and observe the notification.

SK.04

Skeptic gate

Active-form expected control, exact marker, cron-disabled replay path, and re-run against 3.1.2 as the fixed control.

HUMAN

Promotion and disclosure

Review source, replay, impact, version range, wording and public-safety boundary before reporting to the vendor.

WPScan scores CVE-2026-15054 at 3.7 Low on CVSS 3.1. The score reflects limited, integrity-only impact — no data disclosure, no availability loss — and an attack that depends on specific form state. It does not require authentication.

3.7
WPScan · CVSS 3.1 Low
CWE-862
Missing authorization
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N

The practical risk is workflow abuse: entries written to forms the operator considers offline, and notification email dispatched from those forms — a spam and data-integrity concern more than a takeover. The AC:H term reflects the token-acquisition step; PR:N confirms no account is needed.

PluginAffected rangeFixed
bit-form (Bit Form)≤ 3.1.1 (all < 3.1.2)3.1.2

Sites that keep no inactive or draft forms have a smaller exposure window, but any Bit Form install below 3.1.2 should upgrade.

The fix is not "hide the endpoint." The durable rule is that the active-state check must run at every endpoint that acts on a form, not only where the form is rendered.

  1. Upgrade to Bit Form 3.1.2 or later, which returns HTTP 403 "Form is not active" for inactive forms across all endpoints.
  2. Enforce the active-state check in the token-issuing action, the submit action, and the cron/workflow path — each independently.
  3. Treat unauthenticated nopriv AJAX handlers as untrusted entry points that must re-validate object state, never inheriting front-end assumptions.
  4. Until patched, review entries and outbound notifications tied to forms that should be inactive, and consider disabling the plugin on sites with sensitive draft workflows.
JULY 2026
Runtime validation completed against the released plugin; active-form and fixed controls retained.
JULY 2026
Coordinated disclosure to the plugin vendor (Bit Apps).
2026-07-09
CVE-2026-15054 published; Charles Vosburgh credited as researcher.
2026-07-09
Added to the WordPress vulnerability database (WPScan).

The bug lived between rendering and processing. The front end knew the form was inactive and hid it. The submission endpoints did not, and acted on it anyway. Concealment was mistaken for enforcement.

The CVE is the identifier. The active-form control is what proved the endpoint had no opinion about form state until 3.1.2 gave it one.
  1. WPScan / WPVDB record for CVE-2026-15054
  2. NVD record for CVE-2026-15054
  3. Bit Form plugin page
  4. CWE-862 — Missing Authorization

Credit: Discovered and reported by Charles Vosburgh. Research was AI-assisted through source mapping, hypothesis generation, runtime construction and skeptical validation; final review and disclosure ownership remained human.