Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / UI

What an app page is allowed to load

same-origin by default · external images allowed · a control may not fetch a third-party origin

Every app page is served with a Content-Security-Policy the browser enforces. Scripts, styles, fonts, workers and data connections must come from the app's own origin; images may additionally come from any `https:` address. A control that tries to reach a third-party origin is refused by the browser, silently — so a vendored library must ship the parts it needs rather than fetch them at run time.

previewuicontrolssecurityauthoring

Summary#

An app page is not an open document. It is served with a Content-Security-Policy, and the browser — not the platform — enforces it. The shape is same-origin by default: the client, every control bundle, every chunk, every font and every data connection comes from the app's own address.

Two deliberate widenings make ordinary content work. Images may come from any https: address, so a document that embeds a remote picture renders. And inline styles are allowed, because that is how the renderer and every editor-style control position things.

The rule with teeth for a control author is the one about fetching: a control may not load code, data or a font from a third-party origin. Vendor what you need — see chunks — assets a control loads on demand, which exists so a library can ship its own parts, including a worker and a .wasm sibling, and still be served from your app.

Description#

What the policy allows#

WhatAllowed fromWhy it is drawn there
Scriptsthe app's own origin, plus one hashed inline bootstrapthe client, control bundles and chunks are all served by your app. There is no unsafe-inline and no unsafe-eval
Stylesthe app's origin, and inlinethe renderer paints style attributes, and controls position themselves with them continuously
Imagesthe app's origin, any https: address, and data:a document that embeds a remote image is ordinary content, and stylesheets legitimately draw small icons as data: SVG
Fontsthe app's origin, and data:your app's web fonts are served by your app; a chunk's stylesheet may inline a face
Connections (fetch, WebSocket)the app's originthe data channel and live updates are all your app's own address
Workersthe app's origina package chunk may start one; it is served from your app like the rest of the package
Framesnothing, in either directionno page embeds another, and no page may be embedded — which is also what stops clickjacking

Plugins (object), and a <base> element that could re-point every relative URL on the page, are refused outright.

Two companion headers ride along: responses are marked nosniff, and the referrer sent to another site is trimmed to your origin — so following a link out of a document does not hand the other site the record id in your page's address.

The failure is SILENT — this is the part worth remembering#

A refused subresource does not raise an error your code can catch. The browser simply does not fetch it, writes a line to the console, and carries on. A feature that lazily loads something therefore does not break — it quietly does nothing, which looks like a bug anywhere except where it is.

So when a control works in isolation and does nothing in an app, open the browser console first. A CSP refusal names the directive and the address it blocked:

Refused to load the script 'https://cdn.example.com/lib.js' because it violates
the following Content Security Policy directive: "script-src 'self' 'sha256-…'".

What this means when you ship a control#

Vendor, do not fetch. A library that hard-codes a CDN address for its own code will be refused. The answer is to ship it as part of your control, which is what a chunk package is for: a directory served under a real base, so the library's own relative imports, new Worker(new URL(…)) and .wasm siblings all resolve exactly as they would on a static host. See chunks — assets a control loads on demand.

That covers more than it sounds like it should — a diagram engine that lazy-loads a renderer per diagram type, or a speech model's WASM runtime, both vendor cleanly. What it does not cover is a library that must reach its own origin at run time, such as one fetching multi-hundred-megabyte model weights from a CDN. There is no way to declare that today; the page's policy refuses it, and that is the current answer rather than an oversight.

Remote images are fine. ![](https://…) in a document, or an image whose address is data, renders normally. Only http: addresses are refused, and those would be blocked as mixed content on a secure page anyway.

Inline styles are fine. Setting a style attribute from a control works, as does anything the renderer paints.

See also#

Related

control — foreign UI controls (charts, grids, maps)

A `control` block declares the contract of a foreign UI widget — a chart, a data grid, a map — that a small JavaScript…

chunks — assets a control loads on demand

A `chunks { }` block declares assets a control ships but does not need at mount — a maths renderer, a diagram engine, a…

The markdown editor kit — a rich editor you opt into

A full rich-text markdown editor — sections, partial saves, a block menu, tables, find and replace, maths and diagrams…