Skip to content

Burp panel — stream a headless desktop app into the sidebar - #1

Merged
HamadYMarafi merged 1 commit into
mainfrom
feat/burp-panel
Aug 7, 2026
Merged

Burp panel — stream a headless desktop app into the sidebar#1
HamadYMarafi merged 1 commit into
mainfrom
feat/burp-panel

Conversation

@HamadYMarafi

Copy link
Copy Markdown
Owner

What

The Live Browser panel streams a browser. This streams an ordinary GUI program that has no web UI at all, into the same sidebar. Burp Suite is the worked example — nothing here is Burp-specific: give any app its own X display, export it with x11vnc, and it docks like every other panel.

app -> Xvfb :98 -> x11vnc :5902 -> websockify :6082 -> nginx /burp/ -> iframe

Same-origin, for the same reason the Live Browser is: a cross-origin frame makes the session cookie third-party, iOS drops it, and the panel renders a login it can never finish.

Two defaults that aren't obvious

Both cost a working panel, and fixing one without the other still leaves it broken:

  • ?path= must carry the route prefix. noVNC derives its socket from window.location, so a bare path=websockify handshakes against /websockify at the app root and 404s.
  • vnc.html, never vnc_lite.html. Lite has no reconnect code at all (grep -c reconnect → 0), so any drop strands the panel until a manual reload. Paired with websockify --heartbeat=25: a headless app's screen is static, an idle panel sends no RFB frames, and proxies close a silent WebSocket at ~100s.

Unit dependencies

BindsTo= rather than Requires=. Requires= propagates a stop but not a start, so stopping the app killed the panel and starting it again left the panel dead. StartLimitIntervalSec=0 lets x11vnc retry through the cold-boot race against Xvfb instead of being marked failed permanently.

Unrelated bug fixed while testing

server/term-backup.sh preferred sites-available and only fell back to sites-enabled when the cp failed — which it never does once a stale sites-available exists. Since sites-enabled is a real file here rather than a symlink, the two drift, and every backup froze a config missing whatever routes had been added since. It now backs up what nginx actually serves.

Verified

  • tools/predeploy.shGATE: GREEN
  • Zero JS errors; panel opens/closes, honours Escape, and mutually excludes with the Live Browser, Files and Library panels
  • sw.js bypass regex matches /burp/, /burp, /burp/vnc.html — not /burping
  • Auto-reconnect proven by killing the live connection and watching a new one appear untouched
  • No secrets: 511 added lines scanned for keys, hostnames, IPs, tokens and credentials — clean

Security

x11vnc runs -nopw. The boundary is the loopback bind plus whatever fronts nginx — documented explicitly in docs/BURP-PANEL.md, along with the warning that the streamed display is as sensitive as the app on it.

The Live Browser panel streams a browser; this streams an ordinary GUI
program that has no web UI at all. Burp Suite is the worked example, but
nothing here is Burp-specific: give any app its own X display, export it
with x11vnc, and it docks in the sidebar like every other panel.

  app -> Xvfb :98 -> x11vnc :5902 -> websockify :6082 -> nginx /burp/ -> iframe

Same-origin for the same reason the Live Browser is: a cross-origin frame
makes the session cookie third-party, iOS drops it, and the panel renders a
login it can never finish.

Two failure modes are baked into the defaults because both cost a working
panel and neither is obvious:

  * ?path= must carry the route prefix. noVNC derives its socket from
    window.location, so a bare path=websockify handshakes against
    /websockify at the app root and 404s.
  * vnc.html, never vnc_lite.html — lite has no reconnect code at all
    (grep -c reconnect returns 0), so any drop strands the panel until a
    manual reload. Paired with websockify --heartbeat=25: a headless app's
    screen is static, an idle panel sends no RFB frames, and proxies close
    a silent WebSocket at ~100s. Fix one without the other and you get
    either constant drops or a panel that dies for good on the first one.

The units use BindsTo= rather than Requires=. Requires propagates a stop but
not a start, so stopping the app killed the panel and starting it again left
the panel dead. StartLimitIntervalSec=0 lets x11vnc retry through the
cold-boot race against Xvfb instead of being marked failed permanently.

Also fixes an unrelated backup bug found while testing this:
server/term-backup.sh preferred sites-available and only fell back to
sites-enabled when the cp FAILED — which it never does once a stale
sites-available exists. Since sites-enabled is a real file here rather than a
symlink, the two drift, and every backup froze a config missing whatever
routes had been added since. It now backs up what nginx actually serves.

Verified: predeploy gate green; no JS errors; panel opens/closes, honours
Escape, and mutually excludes with the Live Browser, Files and Library
panels; sw.js bypass regex matches /burp/ but not /burping.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@HamadYMarafi
HamadYMarafi merged commit bfac0f6 into main Aug 7, 2026
3 checks passed
@HamadYMarafi
HamadYMarafi deleted the feat/burp-panel branch August 7, 2026 05:18
HamadYMarafi added a commit that referenced this pull request Sep 7, 2026
…1) (#1)

The Live Browser panel streams a browser; this streams an ordinary GUI
program that has no web UI at all. Burp Suite is the worked example, but
nothing here is Burp-specific: give any app its own X display, export it
with x11vnc, and it docks in the sidebar like every other panel.

  app -> Xvfb :98 -> x11vnc :5902 -> websockify :6082 -> nginx /burp/ -> iframe

Same-origin for the same reason the Live Browser is: a cross-origin frame
makes the session cookie third-party, iOS drops it, and the panel renders a
login it can never finish.

Two failure modes are baked into the defaults because both cost a working
panel and neither is obvious:

  * ?path= must carry the route prefix. noVNC derives its socket from
    window.location, so a bare path=websockify handshakes against
    /websockify at the app root and 404s.
  * vnc.html, never vnc_lite.html — lite has no reconnect code at all
    (grep -c reconnect returns 0), so any drop strands the panel until a
    manual reload. Paired with websockify --heartbeat=25: a headless app's
    screen is static, an idle panel sends no RFB frames, and proxies close
    a silent WebSocket at ~100s. Fix one without the other and you get
    either constant drops or a panel that dies for good on the first one.

The units use BindsTo= rather than Requires=. Requires propagates a stop but
not a start, so stopping the app killed the panel and starting it again left
the panel dead. StartLimitIntervalSec=0 lets x11vnc retry through the
cold-boot race against Xvfb instead of being marked failed permanently.

Also fixes an unrelated backup bug found while testing this:
server/term-backup.sh preferred sites-available and only fell back to
sites-enabled when the cp FAILED — which it never does once a stale
sites-available exists. Since sites-enabled is a real file here rather than a
symlink, the two drift, and every backup froze a config missing whatever
routes had been added since. It now backs up what nginx actually serves.

Verified: predeploy gate green; no JS errors; panel opens/closes, honours
Escape, and mutually excludes with the Live Browser, Files and Library
panels; sw.js bypass regex matches /burp/ but not /burping.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant