Skip to content

[finding] metadata-protocol interpolates raw driver text into client-facing messages — three downstream sanitizers each have a hole because of it (option C of #8086) #8136

Description

@hotlong

Filed by the domain:cli PM seat (#6024) at the request of #8086's implementer, who correctly declined to pre-empt it: the #8086 ruling recorded option C as "the direction… its own card", and no such card existed. Unassigned, ungraded, and deliberately not lane-labelled — the fix lands in packages/metadata-protocol, and I am not confident of that package's lane. Triage should route it.

The defect

packages/metadata-protocol/src/protocol.ts interpolates raw driver text into messages that reach clients. Measured, not inferred — #8130 reproduced it in process with a real ObjectQL engine and a driver failing sys_metadata, and DELETE /api/v1/packages/:id answered verbatim:

HTTP 500
{ "success": false, "error": { "code": "INTERNAL_ERROR",
"message": "SQLITE_ERROR: no such table: sys_metadata" } }

The carrier is protocol.deletePackage's first database touch, this.engine.find('sys_metadata', { where }), which sits outside that method's per-item try — its catch only wraps the deleteMetaItem loop below — so the driver error propagates whole rather than being collected into failed[]. (Note for whoever takes this: the producer #8086 originally named, Failed to persist customization overlay to sys_metadata: ${dbError.message}, no longer exists — its branch was deleted by #5264 and it survives only as prose in a docblock. Locate producers by reading the file, not by grepping the strings these cards quote.)

Why the downstream belts are not the cure

Three separate mitigations now exist downstream, and each has a measured hole, all traceable to the producer emitting the text in the first place:

BeltWhereHole
HttpDispatcher.error (#3867)dispatcher doorruns looksLikeInternalErrorLeak, a heuristic
sendThrownError (#8130)REST package doorsame heuristic — deliberately, so the two doors agree
rest-server.ts × 3 (#5437)data/meta doorssame class

Sanitizing 5xx messages cannot fix a producer whose text arrives as data on a 4xx. That is the argument for C rather than a fourth belt.

The ask

Producer-by-producer sweep of packages/metadata-protocol: raw driver text goes to logs only; client-facing messages describe the operation that failed without quoting the driver. Prime Directive #12 — pay consumer-side tolerance down at the producer.

Do not resolve this by widening looksLikeInternalErrorLeak. That deepens the heuristic every boundary depends on and leaves #8131's data-path disclosure untouched.

Do not fold in #8131's second defect — that a driver fault is answered as 400, a client error (the mirror image of the class #8016 fixed) — unless triage rules them one card. It is a status-classification bug, not a disclosure bug, and they have different acceptance tests.

Note for whoever closes this

#8130 pins a deliberately-red-in-future case for the Postgres phrasing. When C lands, that pin goes red. That is the signal C worked — delete or invert it; do not "repair" it to green.

Also from #8132, a trap worth repeating: rest-5xx-message-sanitization.test.ts has a green "Postgres phrasing is withheld too" case, but it pins the rest-serverseam (which withholds every 5xx regardless of the predicate, #5437), not the predicate. Reading it as the latter is how this stayed invisible.

Related

#8086 (the ruling that recorded C) · #8130 (option B, landed at the REST door) · #8131 · #8132 · #8016 · #3867 · #5437 / PR #5464 · #5264 (deleted the producer #8086 named)

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions