Skip to content

v1.37.0 — vecline serve: Office conversion without uploading

Choose a tag to compare

@shunyagatha shunyagatha released this 15 Aug 05:39
· 32 commits to main since this release

A browser tab has no office engine. The two usual ways to give it one each cost something this project is built on: a ~300 MB LibreOffice-in-WASM destroys instant load, and uploading the document destroys the privacy claim outright.

So neither. vecline serve runs a tiny loopback endpoint, and Vecline Studio hands the document to your machine:

npm install -g vecline && vecline serve

Every link stays local:

.docx → your LibreOffice → PDF → mupdf in the tab → pixels → traced SVG

Two endpoints, both taking bytes and returning bytes. No request field anywhere names a file, so there is nothing to traverse or overwrite.

Built to be attacked, then actually attacked

Four agents worked distinct threat classes — hostile web page, input handling, auth, and the LibreOffice boundary — and every claimed finding was independently re-tested against a live server before being believed. No breached boundary. Four hardening gaps, all fixed before release:

  • A failed conversion returned LibreOffice's raw error, carrying both temp directory layouts, the resolved soffice path and hence the OS account name — script-readable by an allowlisted origin. Only messages written for a person are sent now; the detail stays on your console.
  • Any loopback origin on any port was allowed, so every other page served from localhost had full bridge access. Now only vecline.xyz and origins named with --allow-origin.
  • Concurrency was unbounded — six concurrent 64 MB bodies took memory from 100 MB to 722 MB. Capped at two, which costs nothing: LibreOffice serialises on one user profile anyway.
  • --token= silently started with authentication off. It now refuses, and --token-file / VECLINE_TOKEN take precedence over the flag, because an argument is readable from the process table by exactly the account a token exists to fence out.

The threat model in the source header was corrected in four places where the review showed it overclaimed — most importantly "nothing to exfiltrate", which the error text falsified.

Two bugs the tests caught that reading would not have

  • The oversize-body path answered mid-upload, racing the still-arriving body. curl coped; fetch reported ECONNRESET and never saw the 413. Past the cap the body is now drained rather than kept.
  • The client-disconnect check tested req.destroyed, which is also true on the happy path once a body is consumed — it rejected every legitimate request until the empty-document test went red.

500 tests · smoke clean · corpus problems: 0

vecline.mcpb is attached — open it with Claude Desktop to install the MCP server in one click.