Glozr docs

Architecture

Security model

Security in Glozr is layered, not conventional. Every tenant query is filtered, every widget request validates its origin, every outbound HTTP fetch is guarded against SSRF, every retrieved chunk is wrapped as data rather than instructions, and every public endpoint is rate-limited.

Overview

Seven defences run continuously: workspace isolation, origin verification, SSRF protection, input sanitization, prompt-injection containment, rate limiting, and encryption at rest. Browser-side, all responses ship with hardened security headers.

Workspace isolation

Every tenant-scoped model uses BelongsToWorkspace or BelongsToAgent, which apply global query scopes automatically. Workspace identity is resolved from the authenticated user or the verified JWT — never from request parameters. See Multi-tenancy.

Origin allow-listing

The widget validates at two checkpoints: when the JWT is issued, and again on every privileged endpoint the JWT can reach. The match is strict: an empty allowed_origins list denies everywhere, otherwise the request's scheme://host must appear in the list exactly. No subdomain inference, no wildcard, no port stripping.

SSRF protection

The crawler is the largest SSRF surface. It defends in depth:

  • Scheme allow-list — only http and https.
  • Hostname pattern blocks — private IPv4 ranges, IPv6 unique-local, link-local, loopback.
  • Cloud metadata block169.254.169.254, metadata.google.internal, etc.
  • DNS rebind detection — re-resolves at fetch time and rejects if the resolved IP shifts into a private range.
  • Redirect re-validation — each hop runs through the full set of checks; redirects can't smuggle the crawler into an internal host.

Content sanitization & prompt injection

Knowledge-base markdown is run through a hardened sanitizer that strips raw HTML and unsafe URI schemes (javascript:, data:, etc.). System prompts wrap retrieved chunks inside source tags and instruct the model explicitly that this is data, not instructions. The widget refuses to render assistant output that contains script tags or event handlers.

Encryption & secrets

API keys, OAuth refresh tokens, and database passwords on sources are encrypted at rest using Laravel's encrypted cast (AES-256-GCM). The widget JWT signing secret is hashed before comparison. Application secrets live only in env vars or the platform-admin App Settings vault.

Rate limiting

Public endpoints carry per-route throttles, ranging from 5/min (forgot-password) to 600/min (widget message stream). The identifier is chosen per route — IP, JWT subject, or email — to defeat the most common abuse pattern for that endpoint.

Browser defences

Every response sets:

  • Content-Security-Policy with no unsafe-inline or unsafe-eval.
  • Strict-Transport-Security with a long max-age.
  • X-Content-Type-Options: nosniff.
  • Referrer-Policy: strict-origin-when-cross-origin.
  • X-Frame-Options: DENY on the dashboard (the widget is iframe-friendly by design).

Note. Report a vulnerability privately at [email protected]. Please don't open public issues for security reports.