open
https://gitlab.synchro.net/main/sbbs/-/issues/1203
`js_ErrorReporter()` in `src/sbbs3/websrvr.cpp` writes every uncaught JavaScript
error — the message text, plus the script's **absolute** filename and line number — into the HTTP response body, in addition to logging it:
```cpp
lprintf(log_level, "%04d %-5s [%s] !JavaScript %s%s%s: %s, Request: %s"
, session->socket, session->client.protocol, session->host_ip, warning, file, line, message, session->req.request_line);
if (content_file_open(session))
fprintf(session->req.fp, "!JavaScript %s%s%s: %s", warning, file, line, message);
```
(same in the `report == NULL` branch above it). This is a useful debugging aid, but sending it to the *client* has three problems:
**1. Information disclosure.** Any remote visitor who can make a script throw learns the server's on-disk layout and the failing source file and line — e.g.
`s:\sbbs\webv4\lib/pages.js line 108`.
**2. Reflected XSS whenever the message contains request data.** The error text is emitted as the page body with the page's own content type (`text/html` for a `.xjs`/`.ssjs` page) and an HTTP **200**, so any `throw` that interpolates a query parameter, header, or cookie becomes a script-injection vector. This was live in stock webv4 until today. Against an unpatched tree:
```
GET /index.xjs?page=<b>bold</b><script>alert(1)</script>.link
HTTP/1.1 200 OK
Content-Type: text/html
!JavaScript s:\sbbs\webv4\lib/pages.js line 108: Error: Invalid page <b>bold</b><script>alert(1)</script>.link,,,s:\sbbs\webv4\mods\pages\
```
The payload runs in the visitor's browser in the BBS's origin, where webv4's login session cookie lives. That particular `throw` is gone as of 791eb3ad3c, but the delivery mechanism is still there for any other stock or sysop-authored page that puts request data in an error message.
**3. Wrong status and corrupted output.** A failed script yields `200 OK` with error text as the body, rather than a 500 — and if the script had already buffered content, the error is appended to a partial page (or to a JSON API response, breaking the parse client-side).
### Suggested fix
Log the error, don't send it. Options, roughly in order of preference:
- Drop the `fprintf()` to `session->req.fp` and let the request fail through the
normal error-document path (`ErrorDirectory`), returning 500.
- Or keep the echo behind a new `[Web]` option defaulting to **off** (something
like `JavaScriptErrorsToClient=false`), for sysops who want it while
developing.
HTML-escaping the message is not a sufficient fix on its own: the response may be JSON or plain text, and the path disclosure remains either way.
— *Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)