Skip to content

Custom HTML and iframe Access

Custom HTML pages, animation frames, reports and dashboards open inside an iframe served from a separate sandbox port (8083 by default). The separate port is an isolation boundary: this content runs with sandbox="allow-scripts", on its own origin.

This page covers the case where one installation is reached both from the local network and from an external address (typically Secure Access). Both access paths can work at the same time, but the browser-side permissions have to be granted for each path separately.

The frame origin is built by the browser, not the server:

${location.protocol}//${location.hostname}:${sandboxPort}

sandboxPort comes from the GET /api/config response. The result: whichever address the user came in on, the frame opens on port 8083 of that same address. The frame therefore always lands on the same host as the application, so host-only cookies reach it.

There are three separate checks, and they are not fed from the same setting. For an access path to work, all three have to recognise it.

SettingWhat it feedsFormat
ins.app.url, ins.sandbox.url, ins.frontend.urlEnters HostAllowlist as an exact origin — CORS and the sandbox Referer/Origin checkOne value each
ins.allowed-hostsAdds a host regex to HostAllowlist; no port constraintA single regex
ins.iframe.allowed-hostsThe main page’s CSP frame-src and frame-ancestors, and the animation external-iframe validationComma-separated list

Because ins.iframe.allowed-hosts has two different consumers, both forms go in the list:

  • The CSP directives want concrete origins (https://host:8083). Those directives have to be a static list: the parent origin is not known when a sandbox response is generated, so the frame origin derived at request time must already be present in the list.
  • The animation external-iframe validation compares the address by its bare host name (host). That validation is fail-closed: if the list is empty, every address is rejected.

This regex replaces the local defaults rather than adding to them. The defaults are:

  • localhost
  • 127.*
  • the Secure Access tunnel network 10.66.66.*

If you do not include these in your own regex, tunnel access — or access from the server itself — that previously worked will break.

  1. Point ins.app.url and ins.sandbox.url at the external address.
  2. Add the local network IP or machine name to the ins.allowed-hosts regex — along with localhost, 127.0.0.1 and the tunnel network (see the warning above).
  3. Add the following to ins.iframe.allowed-hosts for every access path:
    • the 8082 and 8083 origins
    • the bare host name
    • the localhost and 127.0.0.1 origins too. These are HostAllowlist defaults, but they do not enter the CSP frame-src on their own; without them, Custom HTML will not open when browsing from the server itself via https://localhost:8082.
  4. For local network access, 8082 and 8083 must be open to inbound connections in the firewall. Tunnel traffic is not subject to the firewall.
  5. If the certificate does not cover the local IP, the browser has to accept the 8083 certificate separately: open https://<local-ip>:8083 directly once. Until it is accepted, the frame stays blank with no error.

Settings go in <install>\config\application.yml, after which the inSCADA service is restarted. No JVM -D parameter and no change to the service definition is needed.

ins:
app:
url: https://<company>.inscada.online
sandbox:
url: https://<company>.inscada.online:8083
allowed-hosts: '^(localhost|127\.0\.0\.1|<escaped-local-ip>|10\.66\.66\.\d{1,3})$'
iframe:
allowed-hosts: >-
https://<company>.inscada.online,
https://<company>.inscada.online:8083,
https://<local-ip>:8082,
https://<local-ip>:8083,
https://localhost:8082,
https://localhost:8083,
https://127.0.0.1:8082,
https://127.0.0.1:8083,
<company>.inscada.online,
<local-ip>,
localhost,
127.0.0.1

Values in angle brackets are placeholders. Inside the regex, the dots of an IP address are escaped (192\.168\.1\.50).

Two lines appear in the startup log:

HostAllowlist: using explicit override regex from ins.allowed-hosts
HostAllowlist initialized. literalOrigins=[...], localPorts=[...], defaultsInEffect=false

defaultsInEffect=false tells you your regex took effect and the defaults no longer apply — which is exactly why step 3 carries its warning.

Then check the Content-Security-Policy response header on each access address: frame-src must contain that address’s :8083 origin.

Finally, open a Custom HTML page or an animation in the browser. That exercises the sandbox origin and the cookie flow end to end.

If a frame does not open, look at the iframe’s src in DevTools first — seeing which address it tried tells you which list is missing it.

SymptomWhat it means
Missing or invalid origin for sandbox content in the logThe address is missing from HostAllowlist — ins.allowed-hosts or the advertised addresses
A frame-src / frame-ancestors CSP violation in the consoleThe address is missing from ins.iframe.allowed-hosts
Frame blank, no errorThe 8083 certificate has not been accepted — open that address directly once
Sandbox port used for illegal API call in the logNormal. The sandbox port rejects /api calls
  1. Add the host to the ins.allowed-hosts regex.
  2. Add https://<host>:8082, https://<host>:8083 and the bare <host> to ins.iframe.allowed-hosts.
  3. Restart the service.