# Plattio Forms 2.0.9 security and runtime review

## Scope

This revision received a static source-code review and targeted hardening pass covering the plugin bootstrap, public form rendering and submission, administrator actions, persistence, uploads, notifications, webhooks, save-and-continue, signatures, PDF documents, Email Builder, Gutenberg, Flatsome UX Builder, and Plattio Builder.

The review is a development-level security assessment and regression check. It is not an independent penetration test, formal certification, or guarantee against vulnerabilities in WordPress core, the web server, themes, or other installed plugins.

## Frontend loading model

Normal public requests use form-aware loading:

| Request/form feature | Frontend resources |
| --- | --- |
| No rendered Plattio Form | No Plattio Forms frontend CSS or JavaScript |
| Basic form | Core form stylesheet and frontend runtime only |
| Select, upload, save-and-continue, supported visual icons | Core resources plus WordPress Dashicons |
| International telephone field | Core resources, Dashicons, and the country dataset |
| Signature field | Core resources plus signature CSS and JavaScript |
| Page break | Core resources plus multi-page CSS and JavaScript |
| Multiple forms | The union of required resources, enqueued once per handle |
| Gutenberg/shortcode/synced pattern | Exact published form IDs are detected before `wp_head` |
| Plattio Builder/reusable Plattio Block | Exact selected form IDs are read from stored layouts before `wp_head` |
| Flatsome UX Builder editor | Builder iframe receives the form runtime and active visual-module assets because the selected form can change live |
| Dynamic widget/theme callback after `wp_head` | Only styles enqueued by the form that actually rendered are printed through the late-style compatibility path |
| Global compatibility setting enabled | Core and active visual-module resources are intentionally loaded site-wide |

The administrator class is not loaded for known public form AJAX routes. Large PDF Documents and Email Builder runtime classes are not loaded on ordinary frontend page views; they are loaded for their administrator screens, their own endpoints, form submission processing, relevant cron work, and WP-CLI.

## Security controls reviewed

### Access control and request integrity

- Privileged AJAX and `admin-post.php` operations use custom capabilities and WordPress nonces.
- Public submission and save-and-continue endpoints validate a published form and a form-specific nonce.
- Tokenized signature/PDF/resume links use high-entropy or keyed tokens and strict token formats.
- PDF access modes are checked server-side; password mode has nonce verification plus per-client and per-document request throttling.

### Input, output, and persistence

- Field values are validated and sanitized from the stored form schema rather than trusting submitted field metadata.
- Confirmation HTML is passed through the WordPress KSES allowlist before it reaches frontend JavaScript.
- Administrator output uses contextual escaping.
- Custom-table queries use prepared values and safe identifier placeholders.
- Calculation expressions use a dedicated parser and do not use `eval()`.
- CSV export protects cells that could otherwise be interpreted as spreadsheet formulas.

### File uploads and generated files

- Public uploads use a centralized site-supported allowlist.
- Executable and active-content extensions such as PHP, HTML, SVG, JavaScript, shell scripts, and binaries are blocked even if entered in settings.
- The server verifies that the temporary path is a real HTTP upload.
- WordPress validates the filename extension and MIME mapping, applies real-type checks where core supports them (including image verification), and requires the resulting extension/MIME pair to match the exact allowed pair.
- File size is enforced server-side using the stricter of the global and field limits.
- Signature input accepts only bounded PNG data URLs and validates decoded image dimensions and content.
- Protected generated files are constrained to plugin-controlled directories and served with fixed content types, `nosniff`, no-referrer behavior, and non-cache headers.

### Network and secrets

- Webhook requests use the safe WordPress HTTP API, reject unsafe URLs, have bounded timeouts/redirects, and store sensitive header values encrypted.
- SMTP and licensing secrets are not exposed to frontend localization.
- No remote frontend font, script, or stylesheet is required by the form runtime.

## Operational notes

- Standard file-upload fields are stored as WordPress Media Library attachments and therefore follow the site's media URL/access model. Only business-required extensions should be allowed. Sites that require private document storage should add a dedicated private-storage policy rather than relying on ordinary Media Library URLs.
- Keep WordPress, PHP, the active theme, and all plugins patched; use HTTPS and least-privilege administrator accounts.
- Configure the optional global asset setting only for an unsupported renderer that cannot be discovered before output.
- High-risk or regulated deployments should add an independent authenticated penetration test and infrastructure review.
