Closed bug report

readme.html iframe: 16000px height cap clips content, and connect-src 'self' blocks the loopback fetch the feature needs

John Lauer · 2mo ago ·closed by Colby Knox

The bareHtml readme variant (sandboxed iframe, scripts enabled) has two undocumented limits that break an interactive readme.html, and the AI hints on repo push / readme registration mention neither.

1. The iframe is hard-capped at 16000px, silently clipping the tail

On the adom/adom-bridge Overview the readme iframe renders at exactly style.height: 16000px (maxHeight: none). My readme.html reports its true height every 1.2s via postMessage({type:"readme-height",height}) + a ResizeObserver, and the true content height is 17317px. So the last 1317px is clipped and unreachable by scrolling. A "Try it live" section I placed near the end (its top at 16541px) was 100% invisible on the page, even though it rendered fine in a direct browser load. The 16000 is a suspiciously round number, so it reads as a fixed cap rather than a response to my height message.

Ask: honor the reported readme-height up to a much higher bound (or remove the cap), so a long readme is not silently truncated. At minimum, surface the cap in the registration hint so authors know to keep content under it.

2. connect-src 'self' blocks the loopback fetch, so a null-origin readme cannot reach a local API

The served readme content (GET /readme/adom/app/adom-bridge?variant=public) carries:

content-security-policy: sandbox allow-scripts ...; default-src 'none'; ...; connect-src 'self' data:; ...

The iframe is sandbox="allow-scripts ..." WITHOUT allow-same-origin, so its origin is opaque (null). With an opaque origin, connect-src 'self' matches nothing external, so every fetch() from the readme is blocked, including a GET to http://127.0.0.1:24680/health.

This breaks the exact feature the readme was built for: Adom Bridge exposes a consent-gated loopback API at http://127.0.0.1:24680, and the whole point of the readme demo is a "Try Web Control (live)" panel that a reader clicks to drive their own machine (each call prompts an Allow/Deny in the app). It works in a direct render (no CSP) but is dead on the wiki page. Adom Bridge already CORS-restricts + human-consents every such call, so allowing the page to REACH loopback does not weaken anything on the wiki side.

Ask: allow connect-src http://127.0.0.1:* http://localhost:* for the readme iframe (globally, or as a per-page opt-in flag on the page/readme). Loopback is a browser secure context, so HTTPS -> http://127.0.0.1 is not mixed-content; the only blocker is this CSP directive.

3. Neither limit is in the AI hints

repo push/readme registration returns: "renders on the Overview in a sandboxed iframe with scripts enabled ... Scripts run; network access does not (inline everything)." That does not explain the 16000px cap, and "network access does not" is ambiguous: it reads as "no external resources", but the real effect is that connect-src 'self' also blocks a LOOPBACK fetch. An author building an interactive readme has no way to learn either limit except by loading the page and finding it broken. Please document both in that hint.

Environment: Windows 11, wiki.adom.inc, readme pushed to adom/adom-bridge, Adom Bridge 2.0.37. Measurements taken via pup (Chrome-for-Testing) against the live page.

3 Replies

John Lauer · 2mo ago

Colby - context plus a working reference, because the web-control feature is real and just needs the CSP opened.

What works (served directly). Adom Bridge exposes a consent-gated loopback API at http://127.0.0.1:24680, and a web page drives the machine with a plain fetch() - no SDK. I have a full test harness that, served from a normal local server, does all of this live against my own machine: detect (GET /health), run any verb (POST /command, each pops an Allow/Deny in the app), stream a long op (POST /command/stream, Server-Sent-Events with live status), and capture an app's FULL window state (list windows, then screenshot each by hwnd). The attached screenshot is it driving KiCad and rendering BOTH of KiCad's windows (Symbol Editor + project manager). It works because a directly-served page has a normal origin and a normal CSP.

The harness (read the integration + the sample JS): https://wiki.adom.inc/api/v1/pages/adom-bridge/files/web-control-demo.html (also committed at adom-inc/adom-bridge -> web-control-demo.html). The bottom section is copy-paste sample JS for each pattern.

What is blocked (embedded in the wiki readme iframe) - the ask. When the SAME page renders as a wiki readme.html (bareHtml variant), it is a sandboxed null-origin iframe served with Content-Security-Policy: ... connect-src 'self' data:. With an opaque origin, connect-src 'self' matches nothing external, so every fetch to 127.0.0.1:24680 is CSP-blocked - even /health. The demo renders but cannot reach Adom Bridge.

Requested fix: allow connect-src http://127.0.0.1:* http://localhost:* for the readme iframe - globally, or as a per-page opt-in flag (e.g. a page setting "allow local API"). Loopback is a browser secure context, so HTTPS to http://127.0.0.1 is not mixed content; Adom Bridge already CORS-restricts and human-consents every call, so allowing the page to REACH loopback weakens nothing on the wiki side. (Plus the 16000px iframe height cap from the issue body: honor the readme-height postMessage up to a higher bound, or the tail of a long readme - including this demo - gets clipped.)

Once connect-src allows loopback, the same harness embedded on the adom-bridge page just works: a reader clicks a button and drives their own machine, with the app prompting Allow/Deny. Happy to hop on a call if useful.

kicad_array

Colby Knox · 2mo ago

Thanks for the precise repro and the measurements. Breaking it into the three parts:

1. The 16000px cap (your 17317px content clipping)

Working as designed, but the design was undiscoverable, which is the real bug. The frame grows to the height your readme-height message reports, bounded by a ceiling. That ceiling was 16000px by default, raised per-page with <meta name="readme-max-height" content="32000">, and nothing told you the ceiling existed. Two fixes:

  • Immediate: add <meta name="readme-max-height" content="32000"> to your readme <head> and all 17317px render.
  • Shipped so it stops biting silently: I raised the default ceiling to 32000px (about 35 screens), so ordinary long content now fits with no meta tag at all. The hard bound stays (a runaway or hostile doc still cannot blow the page up without limit), it just sits well above real content.

2. connect-src blocks the loopback fetch

This one cannot be fixed the way the ask proposes, and it is worth being exact about why, because two walls stack:

  • The readme iframe has an opaque origin on purpose (the sandbox has no allow-same-origin). Opening connect-src to 127.0.0.1 would let the fetch leave, but it would carry Origin: null, and Adom Bridge's own CORS allowlists exactly https://wiki.adom.inc, never null. ab would reject it. Making it work would mean loosening ab to accept null, which lets any null-origin context (a file:// page, any sandboxed frame anywhere) drive the bridge.
  • Giving the iframe allow-same-origin so ab accepts it would make every publisher's readme.html run as wiki.adom.inc: a stored XSS reading readers' wiki sessions. That opaque origin is the security boundary and cannot move.

The safe path is parent-mediated: the readme posts the intent to the parent, and the wiki page itself (real wiki.adom.inc origin, which ab already CORS-allows) makes the consent-gated loopback call. That is a real feature (the "Web Control on wiki pages" work), not a CSP flag, and it is in progress rather than something to open up here. When it lands, your "Try it live" panel works through that channel, with ab's per-call Allow/Deny intact. Until then, a readme cannot reach the loopback directly, by design.

3. The hints did not mention either limit

Fixed. The README_HTML_REGISTERED hint on repo push now spells out the auto-resize contract (the readme-height reporter), the height ceiling, and that connect-src is the wiki origin only, so an author learns the sizing and the sandbox boundary from the publish output instead of by loading a broken page. The old ambiguous "network access does not" wording is gone. The same material is now in the adom/wiki skill's readme.html section.

Colby Knox · 2mo ago

Both undocumented limits are fixed and live on prod. (1) The 16000px iframe cap was raised to 32000px (~35 screens), and the readme.html registration hint now teaches the auto-resize contract (the readme-height reporter) plus the max-height meta, so the height is no longer a silent clip. (2) connect-src: a readme can now reach its OWN public back-end by declaring page.json applet_connect (public https origins only; PR #279, shipped prod, SSRF-guarded), and the readme push hints document it. Reaching the reader's LOCAL machine (a bridge / open-in-KiCad button) is by design NOT a connect-src widening; that is the parent-brokered Quick Actions / Web Control track, parked (see #135). The push hints that used to mention neither limit now cover both (README_HTML_REGISTERED for sizing, APPLET_CONNECT_DECLARED for the back-end allowlist). Closing; the local-machine bridge rides Quick Actions.

Log in to reply.