Widget Security

NodeLoom widgets are protected by multi-layer XSS sanitization, CSS security filtering, rate limiting, token-based authentication, and visitor metadata sanitization. This defense-in-depth approach ensures that widgets are safe to embed on any website.

Multi-Layer XSS Sanitization

Widget content passes through three independent sanitization layers. Each layer operates at a different point in the data flow, ensuring that even if one layer is bypassed, the others catch malicious content.

LayerWhereWhat It Does
Layer 1: BackendServer-sideStrips script tags, iframe elements, event handler attributes (onclick, onerror, etc.), and other dangerous HTML before storing content in the database.
Layer 2: DashboardClient-side (dashboard)Sanitizes content when previewing widget customizations in the dashboard. Protects admins from XSS in user-submitted content during configuration.
Layer 3: Widget EmbedClient-side (visitor page)Sanitizes all rendered content in the embedded widget before it reaches the visitor's browser DOM. This is the final defense layer.

Defense in depth

The multi-layer approach ensures that a vulnerability in any single sanitization layer does not compromise security. Backend sanitization prevents storage of malicious content, dashboard sanitization protects admins, and widget-embed sanitization protects end visitors.

Backend Sanitization

The backend sanitizer uses an allowlist that permits common formatting tags (bold, italic, links, lists, tables) while stripping dangerous elements. NodeLoom extends this allowlist to also permit style and class attributes on all elements, which are needed for custom branding.

Stripped by backend sanitizer
<script>alert('xss')</script>          → removed entirely
<iframe src="evil.com"></iframe>       → removed entirely
<img onerror="alert(1)" src="x">      → <img src="x">
<a onclick="steal()">click</a>        → <a>click</a>
<div onmouseover="exploit()">         → <div>

Client-Side Sanitization

Both the dashboard preview and the widget embed sanitize content before rendering. The client-side sanitizer handles edge cases like mutation XSS, encoding tricks, and browser-specific parsing quirks.

CSS Sanitization

Custom CSS entered by widget administrators is sanitized to remove dangerous properties and values that could be used for code execution or data exfiltration.

Blocked PatternRiskExample
expression()Executes JavaScript in older IE versions.width: expression(alert(1))
@importLoads external stylesheets that could contain malicious rules.@import url(evil.css)
-moz-bindingLoads XBL bindings that can execute JavaScript in Firefox.-moz-binding: url(exploit.xml#xss)
javascript: URLsExecutes JavaScript when used in CSS url() values.background: url(javascript:alert(1))

CSS is powerful

Even without JavaScript execution, CSS can be used for clickjacking, content overlay, and UI redress attacks. NodeLoom's CSS sanitization focuses on preventing code execution while allowing legitimate styling.

Rate Limiting

Widget API endpoints are protected by rate limiting to prevent abuse and denial-of-service attacks. Limits are enforced per widget token and per visitor identifier.

Rate limits are configurable per widget from the dashboard. When a limit is exceeded, the API returns HTTP 429 (Too Many Requests) and the widget displays a user-friendly cooldown message.

Token Authentication

Every widget request is authenticated using a unique widget token. The token identifies the widget configuration, connected workflow, and workspace. Invalid or revoked tokens receive HTTP 401 responses.

Widget tokens can be revoked and regenerated from the dashboard at any time. Revoking a token immediately disables the widget on all pages where it is embedded. A new token must be deployed to resume operation.

Visitor Metadata Sanitization

The widget collects minimal metadata about visitors (browser type, page URL, referrer) to provide context to the AI agent. This metadata is sanitized before being processed:

ProtectionDescription
Size limitsEach metadata field is capped at a maximum length to prevent oversized payloads. Fields exceeding the limit are truncated.
Entry limitsThe total number of metadata entries per session is capped. Additional entries beyond the limit are discarded.
Type validationMetadata values are validated to match expected types (string, number, boolean). Unexpected types are rejected.
HTML strippingAny HTML in metadata values is stripped to prevent injection through metadata fields.

Minimal data collection

The widget is designed to collect the minimum amount of visitor data needed for the AI agent to function. No tracking cookies, no fingerprinting, and no third-party analytics are included in the widget bundle.