Burp panel — stream a headless desktop app into the sidebar - #1
Merged
Conversation
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
force-pushed
the
feat/burp-panel
branch
from
August 7, 2026 05:15
01c91d3 to
d8aa38b
Compare
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.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 fromwindow.location, so a barepath=websockifyhandshakes against/websockifyat the app root and 404s.vnc.html, nevervnc_lite.html. Lite has no reconnect code at all (grep -c reconnect→ 0), so any drop strands the panel until a manual reload. Paired withwebsockify --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 thanRequires=.Requires=propagates a stop but not a start, so stopping the app killed the panel and starting it again left the panel dead.StartLimitIntervalSec=0lets x11vnc retry through the cold-boot race against Xvfb instead of being marked failed permanently.Unrelated bug fixed while testing
server/term-backup.shpreferredsites-availableand only fell back tosites-enabledwhen thecpfailed — which it never does once a stalesites-availableexists. Sincesites-enabledis 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.sh→ GATE: GREENsw.jsbypass regex matches/burp/,/burp,/burp/vnc.html— not/burpingSecurity
x11vncruns-nopw. The boundary is the loopback bind plus whatever fronts nginx — documented explicitly indocs/BURP-PANEL.md, along with the warning that the streamed display is as sensitive as the app on it.