CVE case study
CVE-2026-16573: Bit Form Stored Active SVG Signature Data Without Sanitization
Bit Form decoded an unauthenticated signature data URI and wrote SVG bytes directly to a public uploads path. Version 3.2.0 sanitizes SVG signatures before storage.
- Severity
- High (7.5)
- Scoring
- CVSS 3.1
- Weakness
- CWE-79
- Affected
- Bit Form versions earlier than 3.2.0
- Remediation state
- Upgrade to Bit Form 3.2.0 or later
- Advisory published
- 27 Jul 2026
Official vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
Why it matters
Bit Form includes a public signature field that can be configured to store signatures as SVG. SVG is an active document format, so the bytes must be treated as markup rather than as an inert image buffer.
The affected form-submission path decoded the visitor's data URI and wrote the result directly into the site's public uploads tree. When that result contained script and was later opened as image/svg+xml, the browser executed it in the site's origin.
WPScan scores the issue High at 7.5. The vector uses High attack complexity because exploitation depends on the form using the non-default SVG signature option and a user opening the stored file.
How I found it
On 22 July 2026, I followed Bit Form's public signature submission from its data URI through base64 decoding to the entry upload directory. The plugin supported SVG as a signature image type but wrote the decoded bytes without an SVG-specific content check.
I confirmed the public submission token was an anti-CSRF value delivered with the form, not an authentication boundary. An ordinary visitor could therefore reach the same signature storage function by design.
In a disposable WordPress lab, the affected function preserved an active-node marker inside the stored SVG and served it as image/svg+xml. The 3.2.0 control removed that node before writing the file.
WPScan withholds its complete operational PoC until 10 August 2026. The reproduction below is limited to the public source diff and a symbolic sanitizer model; it contains no executable SVG payload or submission request.
Root cause
getSignatureFilePath() selected the file extension from the configured image type, split the submitted data URI, base64-decoded its second part, and passed the resulting bytes to file_put_contents().
The public submission token prevents cross-site form submission but is rendered to ordinary visitors. It does not authenticate the signer and is not a content-safety boundary.
Version 3.1.4 had no SVG-specific sanitizer between decode and write. The upload directory and web server then preserved the active MIME type needed for browser interpretation.
Source-to-sink trace
- 01Public source
bitforms_submit_form signature fieldAn unauthenticated form visitor can supply the signature data URI through the normal submission workflow.
- 02Active format selection
Signature field imgTyp = image/svg+xmlThe built-in field option selects SVG and maps it to an .svg output file.
- 03Decode boundary
getSignatureFilePath() before 3.2.0The handler split and base64-decoded attacker-controlled data without inspecting SVG elements or attributes.
- 04Persistent sink
file_put_contents() in a public entry upload directoryThe decoded document was stored under the active SVG media type and later reachable as a site-origin file.
- 05Fixed content boundary
enshrined SVG Sanitizer in 3.2.0The patch sanitizes decoded SVG bytes, rejects unsafe output, and writes only the cleaned document.
Safe proof of concept
Prerequisites
- Public Bit Form 3.1.4 and 3.2.0 FormManager source.
- Python 3 for the symbolic decode-sanitize-write model.
- No WordPress site, browser, form token, upload directory, or executable SVG content.
Step-by-step reproduction
- Compare
getSignatureFilePath()between 3.1.4 and 3.2.0. Identify the new SVG Sanitizer import, sanitize call, and rejection branch. - Run the symbolic model below. The string
ACTIVE_NODE_MARKERrepresents content a format-aware sanitizer must remove; it is not an SVG element or browser payload. - Confirm that the affected model writes the marker unchanged after decode.
- Confirm that the fixed model removes the marker before the simulated write.
- Use
SAFE_PATH_ONLY_SIGNATUREas the positive control and confirm both models preserve it.
Compare the public signature storage paths
LAB_DIR=$(mktemp -d "\${TMPDIR:-/tmp}/bit-form-cve.XXXXXX")
curl -fsSL \
https://plugins.svn.wordpress.org/bit-form/tags/3.1.4/includes/Core/Form/FormManager.php \
-o "$LAB_DIR/affected.php"
curl -fsSL \
https://plugins.svn.wordpress.org/bit-form/tags/3.2.0/includes/Core/Form/FormManager.php \
-o "$LAB_DIR/fixed.php"
diff -u "$LAB_DIR/affected.php" "$LAB_DIR/fixed.php"Symbolic decode-sanitize-write model
import base64
symbolic_document = "SAFE_PATH ACTIVE_NODE_MARKER"
encoded = base64.b64encode(symbolic_document.encode()).decode()
def affected(data):
return base64.b64decode(data).decode()
def fixed(data):
decoded = base64.b64decode(data).decode()
return decoded.replace("ACTIVE_NODE_MARKER", "")
print("affected stored:", affected(encoded))
print("fixed stored: ", fixed(encoded))Expected evidence
- The public source diff shows that 3.2.0 inserts format-aware sanitization between decode and file write.
- The affected symbolic result retains
ACTIVE_NODE_MARKER. - The fixed symbolic result contains only
SAFE_PATH. - No active SVG document, browser payload, or upload is produced.
Encode only SAFE_PATH_ONLY_SIGNATURE. Both models should return the same harmless string, demonstrating that the fixed boundary preserves ordinary signature content.
On Bit Form 3.2.0 or later, an SVG signature containing a harmless lab-only disallowed-node marker must be stripped or rejected before persistence, while a path-only signature remains usable.
Impact
An unauthenticated visitor could store an active SVG at a public URL when the target form used SVG signatures. Script execution required a victim to open that stored file, such as during entry review.
Execution occurs in the site's origin and can act with the viewing browser's authority. The study keeps the reproduction inert and does not include a reusable session-access payload.
Fix and retest
Upgrade to Bit Form 3.2.0 or later. The fixed code sends SVG signature bytes through enshrined\svgSanitize\Sanitizer, rejects an invalid result, and only then writes the cleaned document.
Defense in depth can include disabling SVG signatures where they are unnecessary, serving user uploads from a separate cookie-less origin, and sending a restrictive content security policy on uploaded documents.
Retest with an inert SVG marker containing a prohibited script node. The affected version preserves that node; the fixed version must remove it while continuing to store a harmless path-only signature.
Engineering lesson
Image handling must follow the semantics of the selected format. A decoded SVG remains executable markup even when the application calls it a signature image.
Validate public upload content after decoding and before persistence. Extension checks and anti-CSRF tokens cannot substitute for format-aware sanitization.