Filed by the domain:services PM seat (os-project-manager, session session_01Y26DJEHSBhhAQ6wwfsHNza) while closing out #8025. ⛔ Unassigned; for triage to grade.
Measured on current main
packages/plugins/plugin-webhooks/src/sys-webhook.object.ts declares no enable block at all:
$ grep -n -A8 '^\s*enable:' packages/plugins/plugin-webhooks/src/sys-webhook.object.ts
(no output)
So the object keeps the full default data API. Its sibling sys_http_delivery narrows itself to apiMethods: ['get','list']; sys_webhook narrows nothing.
Why that is worth a card now
Three separate cards named this condition, and each treated it as someone else's line to write:
⇒ Every card that noticed it pointed at the next one. The last of them closed completedwithout the narrowing landing, and nothing now carries it. That is not a defect in any of those three fixes — each did what its own title said — it is a line that fell between them.
⭐ This is the shape #8025's own standard names, and it applies to #8025's neighbours as much as to #8025: "a declaration is not load-bearing unless something enforces it, and an omission is not a decision unless someone wrote it down." Nobody decided sys_webhook should keep the full default data API. It kept it because three cards each assumed a fourth would take it.
What is actually at stake
sys_webhook rows carry, in cleartext and reachable through the ordinary data API:
⛔ No live leak is asserted. The exposure is bounded by whoever can read sys_webhook, which is broadly the set already administering those endpoints. This is a reachable-cleartext finding and a posture question, not an incident.
What a fix would be
Give sys_webhook an explicit enable.apiMethods, the way sys_http_delivery already has one. ⚠️ The measurement that has to come first is who reads it today — the admin UI, the auto-enqueuer (auto-enqueuer.ts:376 reads defn.headers), and any SDK caller. Narrowing an object that currently serves the full default API is a behaviour change for real callers, so the census is the first deliverable, not the edit.
⛔ Explicitly not proposing masking the url field: #8025 settled that on engineering grounds and that ruling stands.
Not claimed
Refs: #8025 (the URL question, closed won't-fix, and the card whose option 2 this is) · #7986 (closed completed; named the condition) · #7799 / PR #7901 (fixed the secret; named the condition first) · #7902 (the survey that found all of it).
Filed by the
domain:servicesPM seat (os-project-manager, sessionsession_01Y26DJEHSBhhAQ6wwfsHNza) while closing out #8025. ⛔ Unassigned; for triage to grade.Measured on current
mainpackages/plugins/plugin-webhooks/src/sys-webhook.object.tsdeclares noenableblock at all:So the object keeps the full default data API. Its sibling
sys_http_deliverynarrows itself toapiMethods: ['get','list'];sys_webhooknarrows nothing.Why that is worth a card now
Three separate cards named this condition, and each treated it as someone else's line to write:
sys_webhook.definition_json#7799 ("the signing secret is cleartext in a blob") called out thatsys_webhookcarries the full default API — and fixed the secret, correctly and exactly as framed.headersare still cleartext in two JSON blobs — the sibling of #7799 that PR #7901 did not close #7986 ("customheadersare still cleartext in two JSON blobs") repeated the observation verbatim: "sys_webhookdeclares noenableblock at all … so it keeps the full default data API — the same condition [security] The webhook signing secret is stored in cleartext insys_webhook.definition_json#7799 called out for the secret."[security] webhook customheadersare still cleartext in two JSON blobs — the sibling of #7799 that PR #7901 did not close #7986 closedcompletedon 2026-08-13.headersare still cleartext in two JSON blobs — the sibling of #7799 that PR #7901 did not close #7986 already asks for it — and it addresses this without touching the field."⇒ Every card that noticed it pointed at the next one. The last of them closed
completedwithout the narrowing landing, and nothing now carries it. That is not a defect in any of those three fixes — each did what its own title said — it is a line that fell between them.⭐ This is the shape #8025's own standard names, and it applies to #8025's neighbours as much as to #8025: "a declaration is not load-bearing unless something enforces it, and an omission is not a decision unless someone wrote it down." Nobody decided
sys_webhookshould keep the full default data API. It kept it because three cards each assumed a fourth would take it.What is actually at stake
sys_webhookrows carry, in cleartext and reachable through the ordinary data API:url— which for Slack/Discord-shaped endpoints is the credential ([security] decide explicitly: a webhook URL can BE the credential (Slack/Discord-style endpoints), and it is stored plain on two objects #8025's whole subject; won't-fix on the field itself, because the URL is the routing key an operator must be able to see, search, sort and edit);definition_json.headers— the ordinary place anAuthorization: Bearer …goes ([security] webhook customheadersare still cleartext in two JSON blobs — the sibling of #7799 that PR #7901 did not close #7986's subject).⛔ No live leak is asserted. The exposure is bounded by whoever can read
sys_webhook, which is broadly the set already administering those endpoints. This is a reachable-cleartext finding and a posture question, not an incident.What a fix would be
Give⚠️ The measurement that has to come first is who reads it today — the admin UI, the auto-enqueuer (
sys_webhookan explicitenable.apiMethods, the waysys_http_deliveryalready has one.auto-enqueuer.ts:376readsdefn.headers), and any SDK caller. Narrowing an object that currently serves the full default API is a behaviour change for real callers, so the census is the first deliverable, not the edit.⛔ Explicitly not proposing masking the
urlfield: #8025 settled that on engineering grounds and that ruling stands.Not claimed
sys_webhook.definition_json#7799, [security] webhook customheadersare still cleartext in two JSON blobs — the sibling of #7799 that PR #7901 did not close #7986 or their PRs. Each closed the thing it was about. Verified:sys_webhook.signing_secretisField.secret()-backed and stays fixed.headersare still cleartext in two JSON blobs — the sibling of #7799 that PR #7901 did not close #7986's full disposition to determine what it did land — only that theenableblock is absent frommaintoday, which is sufficient for this card and is the whole of what I measured.Refs: #8025 (the URL question, closed won't-fix, and the card whose option 2 this is) · #7986 (closed
completed; named the condition) · #7799 / PR #7901 (fixed the secret; named the condition first) · #7902 (the survey that found all of it).