HTTP security response headers
Every response Myra AI Workspace serves to a browser carries a set of HTTP security headers that harden the web application against common client-side attacks (cross-site scripting, clickjacking, protocol downgrade, MIME-type confusion). They are applied at the edge/application tier and require no configuration by tenants.
Headers at a glance
| Header | Value (application UI) | Protects against |
|---|---|---|
Content-Security-Policy |
see below | cross-site scripting, data exfiltration, unwanted framing |
Strict-Transport-Security |
max-age=63072000; includeSubDomains |
protocol downgrade / SSL-stripping |
X-Frame-Options |
SAMEORIGIN |
clickjacking |
X-Content-Type-Options |
nosniff |
MIME-type confusion attacks |
X-Robots-Tag |
noindex, nofollow — on the public share page (URLs under /shared/…) and the Outlook add-in task pane (/outlook/) |
a private transcript reachable by an unguessable link, or the add-in pane, being indexed by a search engine |
Strict-Transport-Security (HSTS) tells the browser to only ever contact the host
over HTTPS for the next two years. X-Content-Type-Options: nosniff stops the
browser from second-guessing a response's declared content type. Both are sent on
every response — the application UI, the API, and the documentation.
Content Security Policy
The application UI is served with a Content Security Policy that constrains where scripts, styles, images, fonts, connections and frames may come from:
default-src 'self';
script-src 'self' 'unsafe-inline' https://mtm.myrasecurity.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob: https://mtm.myrasecurity.com;
media-src 'self' data: blob:;
font-src 'self' data:;
connect-src 'self' <the environment's API hosts> https://mtm.myrasecurity.com;
worker-src 'self';
frame-src 'self' <the environment's admin API hosts>;
frame-ancestors 'self';
object-src 'none';
base-uri 'self';
form-action 'self'
Why each directive is shaped this way:
default-src 'self'— the baseline: by default a page may only load resources from its own origin. Every exception below is deliberate and enumerated.img-src 'self' data: blob:— the UI renders several images as inlinedata:/blob:URLs rather than separate network requests: AI-generated images from the code interpreter, uploaded attachment thumbnails, the in-app tenant logo, and the pre-auth login logo. The login logo is fetched overconnect-src(as JSON) and rendered as adata:URL for exactly this reason — a cross-host<img src>to the admin/auth asset host would be blocked in a split-host deployment. Notably, wildcardhttps:is excluded — an image referenced by an arbitrary external URL inside model or document output is never auto-loaded (it is shown as inert text instead), which closes a zero-click tracking/exfiltration channel. The single host-specific exception ishttps://mtm.myrasecurity.com(the Matomo analytics image beacon — see below); no other external host may load an image.media-src 'self' data: blob:— audio/video elements load only from the app's own origin and inlinedata:/blob:sources. The read-aloud (text-to-speech) feature fetches synthesized audio and plays it from ablob:object URL; sandboxed artifacts may inline smalldata:/blob:media. As withimg-src,https:is excluded, so an external<audio>/<video>URL in model or document output is never auto-loaded — the same zero-click-exfiltration close. (Without this directive, media falls back todefault-src 'self', which does not coverblob:, and read-aloud is blocked outright.)connect-src— the UI may only open network connections (data fetches, chat streaming, error reporting) to its own origin and the API hosts for its environment, plushttps://mtm.myrasecurity.comfor the Matomo analytics beacon (see below). Connections to any other host are blocked — including the FX rate source: the daily USD→EUR exchange rate for cost display is fetched by the gateway server-side and served from the API, so no third-party FX host appears in the policy.frame-src— the UI embeds two kinds of frames: interactive artifacts produced by the assistant (rendered in a locked-down, script-only sandbox) and inline previews of documents such as PDFs served by the admin API. Both are permitted; nothing else.object-src 'none',base-uri 'self',form-action 'self',frame-ancestors 'self'— hardening: no legacy plugin embeds, no<base>hijacking, forms may only submit to the application itself, and the application may not be embedded in a frame by another site (an additional clickjacking control alongsideX-Frame-Options).
Why script-src allows inline scripts
script-src permits 'unsafe-inline' rather than pinning specific script hashes.
This is a deliberate, necessary trade-off for the assistant artifact feature:
interactive artifacts (for example an assistant-authored React component or an HTML/SVG
preview) run untrusted, model-authored code inside a sandboxed frame with an opaque
origin and no access to cookies, storage, or the parent page. Such a frame inherits
the parent page's Content Security Policy, so a hash- or nonce-based script-src would
block the artifact's own inline scripts and the feature could not run at all. The
untrusted artifact code is instead contained by the sandbox itself and by the frame's
own stricter policy (it is permitted no network access — connect-src 'none'),
which is where the real isolation boundary lives. That per-frame policy applies to every
artifact kind — the interactive React preview as well as the HTML and SVG previews.
script-src still forbids eval and forbids loading scripts from any external origin
except the single enumerated Matomo analytics host (see below).
Matomo analytics (https://mtm.myrasecurity.com)
The public web surfaces load Matomo Tag Manager for product
analytics. This adds one host-specific external origin, https://mtm.myrasecurity.com
(a Myra-operated domain), to three directives — script-src (the container and tracker
JavaScript), img-src (the image-beacon fallback), and connect-src (the matomo.php
tracking beacon). All three target that one host; no other external origin is permitted,
so the policy stays otherwise closed.
The web app loads the tracker only on the production host (ai.myra.eu); the
documentation site loads its own container on ai-docs.myra.eu / ai-docs-beta.myra.eu.
In the web app it is also skipped when a session starts on a shared-conversation link
(/shared/*, the token is part of the path), and the loader never injects the container
script twice. A hostname gate means it never loads on beta, internal, development, CI, or
preview builds, so those are permitted by the CSP but never actually inject it. Matomo is
operated by Myra; its cookie and consent configuration is documented in the privacy policy.
Because that per-frame policy also blocks stylesheets, web fonts, remote images and API
calls, an artifact has to be self-contained to render at all. The assistant's
instructions state this constraint explicitly, so a generated artifact inlines its CSS and
JavaScript and embeds images and fonts as data: URIs rather than fetching them.
The same containment applies when an artifact is opened in its own browser tab: that tab is an application page which hosts the artifact in the identical sandboxed frame and labels it as AI-generated content. The artifact document itself is never the tab's own page.
The API and documentation
The inference and admin APIs return JSON and streamed data that browsers do not apply
a page CSP to, so they carry HSTS and nosniff plus targeted framing controls rather
than the full application policy. The admin API deliberately permits the application UI
to frame its document downloads (so inline PDF preview works) while still blocking
framing by any third-party site. The documentation site carries HSTS, nosniff and
X-Frame-Options: SAMEORIGIN.
The Office add-in task pane (/outlook/)
The Office.js Outlook add-in task pane is served on the application origin under
/outlook/ but carries its own Content Security Policy (OUTLOOK_CSP), because the
application policy's frame-ancestors 'self' would prevent Microsoft Outlook from embedding
the pane in its webview. This one location deliberately differs from the application policy:
frame-ancestorslists the Microsoft-owned Office-web host origins (https://*.cloud.microsoft,https://*.officeapps.live.com,https://*.office.com,https://*.office365.com) — never a broad*.microsoft.comwildcard — so only Microsoft's Office surfaces may frame it.*.cloud.microsoftis required because Office-on-the-web is migrating to the unifiedcloud.microsoftdomain (completing ~mid-2025); without it the pane would be refused framing (a blank pane) as that rollout lands (AGF-3083).X-Frame-Optionsis omitted for this location (it conflicts with cross-origin framing;frame-ancestorsis the modern control).script-src 'self' https://appsforoffice.microsoft.comallows the Office.js library from Microsoft's CDN and forbids'unsafe-inline'(tighter than the application policy — the pane has no artifact-sandbox requirement). The pane's own logic ships as a built bundle.connect-srcreaches only the direct action lane (https://ai-api*.myra.eu).- The pane renders all model and mailbox output with
textContent(neverinnerHTML), so an untrusted model response cannot inject script into this same-origin surface.
OUTLOOK_CSP is a sanctioned CSP value kept byte-identical across the SPA confs and enforced by
scripts/lint_security_headers.sh alongside the application, admin and monitor policies.
The Office add-in task pane (/excel/)
The Office.js Excel add-in task pane (AGF-2823) is served under /excel/ and carries its own
Content Security Policy (EXCEL_CSP), for the same reason as the Outlook pane — the application
policy's frame-ancestors 'self' would prevent Excel from embedding it. EXCEL_CSP is now
byte-identical to OUTLOOK_CSP (and WORD_CSP):
frame-ancestorsis the modern full Office-web set —https://*.cloud.microsoft,https://*.officeapps.live.com,https://*.office.com,https://*.office365.com(AGF-3083; previously least-privilege to only*.officeapps.live.com, which would refuse framing as Excel-web migrates tocloud.microsoft). Desktop Excel (WebView2) does not enforceframe-ancestors.X-Frame-Optionsis omitted for this location (same rationale as Outlook).script-src,connect-src, and the other directives are the same asOUTLOOK_CSP.- The pane renders all model output and its cell preview with
textContent/createElement(neverinnerHTML); untrusted model output written into cells is additionally neutralised against formula injection (apostrophe + textnumberFormat; a formula-write is screened) — see Direct document-AI actions.
EXCEL_CSP is a sanctioned CSP value kept byte-identical across the SPA confs and enforced by
scripts/lint_security_headers.sh (Check 1 sanction + the /excel/ arm of the inheritance check).
The Office add-in task pane (/word/)
The Office.js Word add-in task pane (AGF-2687) is served under /word/ and carries WORD_CSP, which
is byte-identical to OUTLOOK_CSP/EXCEL_CSP — the same modern Office-web frame-ancestors set
(*.cloud.microsoft + *.officeapps.live.com + *.office.com + *.office365.com), Office.js CDN in
script-src, and connect-src to the direct action lane. The pane renders model output via
textContent and inserts into the document only through safe Word APIs (insertText/insertParagraph
— never a live hyperlink/image/HTML sink); see
Direct document-AI actions. WORD_CSP is sanctioned +
lint-guarded (Check 1 + the /word/ arm) exactly like the other two.
The three Office add-in CSPs are currently identical; they are kept as three sanctioned values so the
scripts/lint_security_headers.shinheritance check can assert each/location/independently.The
/privacy.html,/tos.htmland/impressum.htmlredirect location (301 to the route, relativeLocation) declares no headers of its own and therefore inherits the server-level set above unchanged.