Proof/CVE-2026-15054
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.
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.
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.
Onload action
Unauthenticated request yields CSRF + identity tokens for an inactive form.
Submit action
Tokens are accepted; an entry is created for the inactive form.
Notifications
Attached workflows execute, including outbound email.
cronNotOk
With WP-Cron off, a replayed token forces explicit workflow execution.
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.
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.
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.
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.
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.
Active form
An active form accepts a submission and runs its workflow — the intended behavior.
Inactive form
The same unauthenticated flow against an inactive form still creates an entry and fires notifications.
3.1.2 endpoints
Token, submit and cron endpoints return HTTP 403 "Form is not active" for inactive forms.
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.
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.
Source mapping
Trace the nopriv token and submit actions and locate every place the form's active state is (and is not) consulted.
Authorization hypothesis
Challenge the assumption that hiding inactive forms on the front end prevents submissions to them.
Runtime construction
Drive the token → submit → workflow flow directly against an inactive form, unauthenticated, and observe the notification.
Skeptic gate
Active-form expected control, exact marker, cron-disabled replay path, and re-run against 3.1.2 as the fixed control.
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.
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.
| Plugin | Affected range | Fixed |
|---|---|---|
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.
- Upgrade to Bit Form 3.1.2 or later, which returns HTTP 403 "Form is not active" for inactive forms across all endpoints.
- Enforce the active-state check in the token-issuing action, the submit action, and the cron/workflow path — each independently.
- Treat unauthenticated
noprivAJAX handlers as untrusted entry points that must re-validate object state, never inheriting front-end assumptions. - 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.
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.
- WPScan / WPVDB record for CVE-2026-15054
- NVD record for CVE-2026-15054
- Bit Form plugin page
- 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.