etchKit is a read-only plugin with a small attack surface. It does not write to the database, does not accept user-generated content on the server, and does not load anything on the public-facing site. Here is the full security model.
Access control #
The plugin’s assets and REST endpoint are only available to logged-in users with the edit_posts capability. That covers editors and administrators by default. Subscribers, contributors, and anonymous visitors cannot access any part of the plugin.
Nonce authentication #
Every REST request from the panel includes a WordPress nonce in the X-WP-Nonce header. The nonce is generated server-side via wp_localize_script and validated by the WordPress REST API layer on each request. This prevents CSRF attacks where a malicious page tries to make requests to the endpoint on the user’s behalf.
No database queries #
The plugin reads a single static JSON file (library/library.json) and caches the result in a WordPress transient. No SQL queries are executed at any point. This eliminates SQL injection as an attack vector entirely.
DOM safety #
All text rendered by the panel uses textContent, which the browser treats as plain text. There is no innerHTML with user-supplied data.
The only innerHTML assignments in the codebase use static, developer-controlled SVG strings from the built-in library. User-provided SVG from custom items (svgCode) is rendered via a data:image/svg+xml URI inside an <img> tag. This means the SVG is treated as an image, not as executable markup. Scripts inside the SVG cannot run.
URL validation #
All external URLs in the library (docs links and iframe preview URLs) are validated client-side against a strict ^https?:\/\/ pattern before use. This blocks javascript: URIs, data: URIs, and other potentially dangerous schemes.
Relative wireframe paths (for SVG images) are validated against a separate pattern that rejects protocol-relative URLs (//example.com) and absolute URLs. Only local relative paths are accepted.
Import validation #
When importing custom items via the Settings menu, the JSON is validated before anything is stored:
- The input must be a valid JSON array of objects
- Each object must have
idandnamefields - Only known schema fields are accepted (field whitelist). Unknown fields are stripped
- Imported IDs are checked against built-in item IDs to prevent collisions. You cannot overwrite a built-in item through import
External links #
All links to external pages include rel="noopener noreferrer". This prevents the linked page from accessing the opener window’s context.
Iframe sandboxing #
Live preview iframes use sandbox="allow-scripts allow-same-origin". Preview URLs are always cross-origin relative to the WordPress install, so this combination does not allow sandbox escape. The iframe can run its own scripts and access its own origin, but it cannot reach into the parent page or the WordPress admin.
Fetch timeout #
The library fetch request is cancelled after 10 seconds via AbortController. If the server is slow or unresponsive, the panel shows an error state instead of hanging indefinitely.
PHP escaping #
All values passed from PHP to JavaScript via wp_localize_script are sanitized with esc_url_raw(). The ?etch query parameter used to detect the builder page is validated with sanitize_key() before use.