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
The direct-mount package door ships 5xx messages verbatim — no leak heuristic, unlike the dispatcher twin and unlike rest-server's own /data exit #8086
Found while implementing #8016 (coded-error mapping on the same door). Recorded rather than acted on: #8016's dispatch explicitly scoped this out, and it is an independent decision about message disclosure, not about status/code mapping. Filed unassigned; nobody is on it.
The gap
packages/rest/src/package-routes.ts writes every error body through the shared sendError (packages/types/src/response-envelope.ts), and neither the module nor the shared writer applies any leak heuristic:
rest-server.ts — three call sites (:1355, :9019, plus the conflict branch at :1052) run the same predicate.
So one door of /api/v1/packages withholds a leaky 5xx message and the other does not, on the same deployment.
Reachability
packageService.publish / .delete and protocol.deletePackage execute inside these handlers, and packages/metadata-protocol/src/protocol.ts interpolates raw driver text into client-facing messages on status: 500 throws — the two producers #5437 named by line (Failed to persist customization overlay to sys_metadata: ${dbError.message}..., Failed to delete customization overlay: ${err.message}). A SQLite/Postgres error naming physical tables is well under any length threshold, so it travels whole.
Before #8016 this door's catch-alls shipped (error as Error).message verbatim on a hard-coded 500; after it they ship the resolved status's message verbatim. The disclosure behaviour is unchanged in both directions — #8016 only stopped mislabelling refusals as faults. What changed is that a coded 5xx now arrives here as a 5xx with its own code, which makes the missing filter easier to reach deliberately.
Sibling, closed
#5437 / PR #5464 fixed exactly this class one seam over (rest-server.ts's resolveErrorResponse passthrough band). That fix did not reach this registrar, which does not go through resolveErrorResponse at all. #3867 is the sanitizer itself.
Directions (not a ruling)
A — sanitize in the shared writer. Apply the 5xx rule inside sendError, so every module that writes the declared envelope inherits it. Widest blast radius (7+ route modules, several services and plugins), and it makes a disclosure rule a property of the envelope writer, which its own module note currently disclaims.
B — sanitize at this door. Apply it in sendThrownError (package-routes.ts). Smallest change, closes the door named here, leaves the other sendError callers unaudited.
A + C, or B + C, are the combinations that leave nothing hanging. Whoever takes it should decide whether "the envelope writer sanitizes" is a rule this repo wants, because that answer generalises and B does not.
Unverified
Read from code and confirmed by grep (looksLikeInternalErrorLeak( has zero call sites in package-routes.ts and in response-envelope.ts). No end-to-end reproduction: I did not boot a REST server and force a sys_metadata write failure through POST /packages/publish.
Found while implementing #8016 (coded-error mapping on the same door). Recorded rather than acted on: #8016's dispatch explicitly scoped this out, and it is an independent decision about message disclosure, not about status/code mapping. Filed unassigned; nobody is on it.
The gap
packages/rest/src/package-routes.tswrites every error body through the sharedsendError(packages/types/src/response-envelope.ts), and neither the module nor the shared writer applies any leak heuristic:package-routes.ts— no call tolooksLikeInternalErrorLeak(it is named only in prose after The direct-mount REST package door answers 500 INTERNAL_ERROR for coded 4xx errors the dispatcher twin maps correctly #8016).packages/types/src/response-envelope.ts—sendErrorwrites{ success: false, error: { code, message } }and nothing else. Deliberately: its module note scopes it to "writing the declared envelope".Both siblings on this surface DO sanitize:
HttpDispatcher.error(packages/runtime/src/http-dispatcher.ts) replaces the message withINTERNAL_ERROR_MESSAGEwhenhttpStatus >= 500 && looksLikeInternalErrorLeak(message)(analytics /query 未做 cube 存在性校验,未注册名直达驱动当表名;且错误路径原样回显驱动 SQL(#3770 同类,另一子系统) #3867).rest-server.ts— three call sites (:1355,:9019, plus the conflict branch at:1052) run the same predicate.So one door of
/api/v1/packageswithholds a leaky 5xx message and the other does not, on the same deployment.Reachability
packageService.publish/.deleteandprotocol.deletePackageexecute inside these handlers, andpackages/metadata-protocol/src/protocol.tsinterpolates raw driver text into client-facing messages onstatus: 500throws — the two producers #5437 named by line (Failed to persist customization overlay to sys_metadata: ${dbError.message}...,Failed to delete customization overlay: ${err.message}). A SQLite/Postgres error naming physical tables is well under any length threshold, so it travels whole.Not a regression from #8016, and not new
Before #8016 this door's catch-alls shipped
(error as Error).messageverbatim on a hard-coded 500; after it they ship the resolved status's message verbatim. The disclosure behaviour is unchanged in both directions — #8016 only stopped mislabelling refusals as faults. What changed is that a coded 5xx now arrives here as a 5xx with its own code, which makes the missing filter easier to reach deliberately.Sibling, closed
#5437 / PR #5464 fixed exactly this class one seam over (
rest-server.ts'sresolveErrorResponsepassthrough band). That fix did not reach this registrar, which does not go throughresolveErrorResponseat all. #3867 is the sanitizer itself.Directions (not a ruling)
sendError, so every module that writes the declared envelope inherits it. Widest blast radius (7+ route modules, several services and plugins), and it makes a disclosure rule a property of the envelope writer, which its own module note currently disclaims.sendThrownError(package-routes.ts). Smallest change, closes the door named here, leaves the othersendErrorcallers unaudited.metadata-protocolstops interpolating driver text into client-facing messages; the raw text goes to logs only. Contract-first and the real cure, but it needs a producer-by-producer sweep — the same option C sendError 的显式状态直通覆盖 400–599,5xx 的原始驱动报错绕过全部泄漏启发式直达客户端(metadata-protocol 有活体产出方) #5437 recorded.A + C, or B + C, are the combinations that leave nothing hanging. Whoever takes it should decide whether "the envelope writer sanitizes" is a rule this repo wants, because that answer generalises and B does not.
Unverified
Read from code and confirmed by grep (
looksLikeInternalErrorLeak(has zero call sites inpackage-routes.tsand inresponse-envelope.ts). No end-to-end reproduction: I did not boot a REST server and force asys_metadatawrite failure throughPOST /packages/publish.Generated by Claude Code