You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Keep raw database error text out of production 500 responses #413
handlePrismaError wraps the original error message in a DatabaseError, and getErrorResponse returns that message to the client in every environment. Only details is hidden outside development. So production 500 responses can carry Prisma messages, constraint names, host and port text, and non-Prisma messages such as a Supabase RPC error.
Severity: Low (information leak)
Area:apps/hocuspocus.server
Source: security review of 2026-10-06
Where
handlePrismaError: apps/hocuspocus.server/src/lib/errors.ts:94-101 puts error.message into DatabaseError (an AppError).
getErrorResponse: apps/hocuspocus.server/src/lib/errors.ts:104-115 returns AppError.message in every environment.
The house envelope lives in apps/hocuspocus.server/src/http/envelope.ts (ok / fail); keep using it (see apps/hocuspocus.server/CLAUDE.md §HTTP Modules).
Fix plan
In handlePrismaError, give DatabaseError a fixed public message, for example "A database error occurred.", and keep the original as cause.
In getErrorResponse, outside development, return the fixed message for DatabaseError and for any non-AppError. Keep the specific message for 4xx AppErrors that are written for users (validation, not found, forbidden).
Log the original message and stack with the requestId on the server, so support can still trace it.
Check callers that build messages from upstream errors (grep RPC failed:) and move the upstream text into cause.
Acceptance criteria
In production mode, a forced Prisma error returns a 500 with the fixed message and a requestId, and no driver text.
The server log has the full original error for that requestId.
changed the title [-]Raw database and Prisma error text appears in production 500 responses[/-][+]Keep raw database error text out of production 500 responses[/+]on Oct 6, 2026
Status: fixed in 355502b on claude/youthful-lovelace-3nvsc6, at the response layer instead of in handlePrismaError. Not merged or deployed yet.
What shipped: outside development, getErrorResponse in apps/hocuspocus.server/src/lib/errors.ts returns Internal server error for every AppError with statusCode >= 500. The code is unchanged. A non-AppError already got that message. 4xx messages are unchanged. apps/hocuspocus.server/API.md documents the rule, and tests/integration/documents.test.ts asserts it.
Differences from the plan:
Steps 1 and 4 were not done. handlePrismaError and the RPC failed: callers still put upstream text into the message. The response layer now hides it, so moving it into cause is not needed.
Step 3 was already in place. app.onError in src/index.ts logs the original error with requestId. handleError in documents.controller.ts logs it without a requestId field; the request log line for the same request has it.
The response body has no requestId. Hono's requestId() middleware sends it in the X-Request-Id response header.
Handlers with their own error shape do not call getErrorResponse, so this fix does not cover them. The OpenAPI notes list them: email handlers, admin middleware, media-upload guards and link metadata.
Module handlers under src/modules/ call fail() from src/http/envelope.ts, which does not mask. Their 5xx messages are fixed strings, such as the persist-failed text, so they carry no driver text. The API.md line "every 5xx error.message is Internal server error" covers getErrorResponse only.
Verify: cd apps/hocuspocus.server && bun test tests/integration/documents.test.ts.
Activity
docs: record the security and push fixes in changelogs and agent docs
[-]Raw database and Prisma error text appears in production 500 responses[/-][+]Keep raw database error text out of production 500 responses[/+]HMarzban commentedon Oct 6, 2026
Status: fixed in
355502bonclaude/youthful-lovelace-3nvsc6, at the response layer instead of inhandlePrismaError. Not merged or deployed yet.What shipped: outside development,
getErrorResponseinapps/hocuspocus.server/src/lib/errors.tsreturnsInternal server errorfor everyAppErrorwithstatusCode >= 500. Thecodeis unchanged. A non-AppErroralready got that message. 4xx messages are unchanged.apps/hocuspocus.server/API.mddocuments the rule, andtests/integration/documents.test.tsasserts it.Differences from the plan:
handlePrismaErrorand theRPC failed:callers still put upstream text into the message. The response layer now hides it, so moving it intocauseis not needed.app.onErrorinsrc/index.tslogs the original error withrequestId.handleErrorindocuments.controller.tslogs it without arequestIdfield; the request log line for the same request has it.requestId. Hono'srequestId()middleware sends it in theX-Request-Idresponse header.getErrorResponse, so this fix does not cover them. The OpenAPI notes list them: email handlers, admin middleware, media-upload guards and link metadata.src/modules/callfail()fromsrc/http/envelope.ts, which does not mask. Their 5xx messages are fixed strings, such as the persist-failed text, so they carry no driver text. TheAPI.mdline "every 5xxerror.messageisInternal server error" coversgetErrorResponseonly.Verify:
cd apps/hocuspocus.server && bun test tests/integration/documents.test.ts.Generated by Claude Code
chore(merge): land the security and push fixes branch
fix: close follow-ups from the security and push review
test(hocuspocus): restore NODE_ENV after the CORS suite
test(hocuspocus): pin production for the 5xx mask case
refactor(hocuspocus): tidy the push, SSRF, error and admin-log follow…
fix(hocuspocus): keep Supabase error text out of admin 500 bodies
docs(hocuspocus): sync server docs with the 9 October fixes