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

  1. 01
    Public sourcebitforms_submit_form signature field

    An unauthenticated form visitor can supply the signature data URI through the normal submission workflow.

  2. 02
    Active format selectionSignature field imgTyp = image/svg+xml

    The built-in field option selects SVG and maps it to an .svg output file.

  3. 03
    Decode boundarygetSignatureFilePath() before 3.2.0

    The handler split and base64-decoded attacker-controlled data without inspecting SVG elements or attributes.

  4. 04
    Persistent sinkfile_put_contents() in a public entry upload directory

    The decoded document was stored under the active SVG media type and later reachable as a site-origin file.

  5. 05
    Fixed content boundaryenshrined SVG Sanitizer in 3.2.0

    The 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

  1. Compare getSignatureFilePath() between 3.1.4 and 3.2.0. Identify the new SVG Sanitizer import, sanitize call, and rejection branch.
  2. Run the symbolic model below. The string ACTIVE_NODE_MARKER represents content a format-aware sanitizer must remove; it is not an SVG element or browser payload.
  3. Confirm that the affected model writes the marker unchanged after decode.
  4. Confirm that the fixed model removes the marker before the simulated write.
  5. Use SAFE_PATH_ONLY_SIGNATURE as 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.
Negative control

Encode only SAFE_PATH_ONLY_SIGNATURE. Both models should return the same harmless string, demonstrating that the fixed boundary preserves ordinary signature content.

Fixed-version re-test

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.

References

Follow this thread

Related research, source, and writing.

These paths share a published research boundary, project source, article series, or authorized lab context with this record.

Back to article start