Context
MainVerticle starts the HTTP server without specifying a listen address:
// web-ui/src/main/java/studio/webui/MainVerticle.java:101
vertx.createHttpServer().requestHandler(router).listen(8080);
Vert.x's listen(int) overload uses the default host, 0.0.0.0: the server is reachable from
every network interface, not just the loopback.
The API mounted at /api has no authentication, and exposes among others:
GET /api/library/packs — lists the local library
POST /api/library/download — returns a pack's contents
POST /api/library/upload — writes a file into the library
POST /api/library/convert — triggers a conversion
POST /api/library/remove — deletes a pack
POST /api/device/addFromLibrary, /removeFromDevice, /dump — drive the connected device
On a shared network — public wifi, a corporate or guest network, a shared flat — any machine on
the same segment can therefore read, write and delete in the user's library while STUdio is
running. Since the application is launched by a script that immediately opens a browser, the
user has no reason to suspect anything is listening beyond the loopback.
The CORS filter at MainVerticle.java:67 (CorsHandler.create("http://localhost:.*")) does not
cover this: CORS is enforced by the browser, on requests issued by a web page. It has no effect
on a direct request from curl, a script, or another application.
Description
Bind the server to the loopback only, which matches what the application is: a desktop tool
whose UI is served at http://localhost:8080 — the very URL MainVerticle opens itself, a few
lines after the listen call.
No functionality is lost: the frontend is served by the same server and loaded from localhost.
A related point, to settle here or in a follow-up: port 8080 is hard-coded. It is very often
already taken, and startup then fails with nothing actionable — listen() with no handler
discards the failure silently. Making address and port configurable (via a system property, as
studio.open already is just below) would address both at once.
Affected files
web-ui/src/main/java/studio/webui/MainVerticle.java — the listen call, plus a failure
handler so that an occupied port is reported
web-ui/src/test/java/studio/webui/ — listen test
README.md / README_fr.md — document the option if one is added
Implementation plan
- Replace
listen(8080) with listen(port, host), host defaulting to 127.0.0.1.
- Read address and port from system properties (
studio.host, studio.port), following the
convention already established by studio.open.
- Pass a handler to
listen: log a bind failure explicitly rather than leaving a process
running that serves nothing.
- Build the browser URL from the effective port instead of the
http://localhost:8080
constant.
- Test: the running server answers on
127.0.0.1 and does not answer on the machine's
non-loopback address.
Acceptance criteria
Complexity
S — the core fix is one line; most of the work is configurability and the test.
Context
MainVerticlestarts the HTTP server without specifying a listen address:Vert.x's
listen(int)overload uses the default host,0.0.0.0: the server is reachable fromevery network interface, not just the loopback.
The API mounted at
/apihas no authentication, and exposes among others:GET /api/library/packs— lists the local libraryPOST /api/library/download— returns a pack's contentsPOST /api/library/upload— writes a file into the libraryPOST /api/library/convert— triggers a conversionPOST /api/library/remove— deletes a packPOST /api/device/addFromLibrary,/removeFromDevice,/dump— drive the connected deviceOn a shared network — public wifi, a corporate or guest network, a shared flat — any machine on
the same segment can therefore read, write and delete in the user's library while STUdio is
running. Since the application is launched by a script that immediately opens a browser, the
user has no reason to suspect anything is listening beyond the loopback.
The CORS filter at
MainVerticle.java:67(CorsHandler.create("http://localhost:.*")) does notcover this: CORS is enforced by the browser, on requests issued by a web page. It has no effect
on a direct request from
curl, a script, or another application.Description
Bind the server to the loopback only, which matches what the application is: a desktop tool
whose UI is served at
http://localhost:8080— the very URLMainVerticleopens itself, a fewlines after the
listencall.No functionality is lost: the frontend is served by the same server and loaded from
localhost.A related point, to settle here or in a follow-up: port
8080is hard-coded. It is very oftenalready taken, and startup then fails with nothing actionable —
listen()with no handlerdiscards the failure silently. Making address and port configurable (via a system property, as
studio.openalready is just below) would address both at once.Affected files
web-ui/src/main/java/studio/webui/MainVerticle.java— thelistencall, plus a failurehandler so that an occupied port is reported
web-ui/src/test/java/studio/webui/— listen testREADME.md/README_fr.md— document the option if one is addedImplementation plan
listen(8080)withlisten(port, host),hostdefaulting to127.0.0.1.studio.host,studio.port), following theconvention already established by
studio.open.listen: log a bind failure explicitly rather than leaving a processrunning that serves nothing.
http://localhost:8080constant.
127.0.0.1and does not answer on the machine'snon-loopback address.
Acceptance criteria
mvn -Dskip.installnodeyarn=true -Dskip.yarn=true testgreen on Linux and WindowsComplexity
S — the core fix is one line; most of the work is configurability and the test.