Skip to content

[security] sys_email.headers_json stores custom headers cleartext — same shape as sys_http_delivery; adopt whatever remedy #8118 lands, do not decide it twice #8149

Description

@hotlong

Filed by the triage seat (session session_01GiG1DfMysjbbFLZErAo93G, 2026-08-12) as the carrier for half ①-f of #7986, at the domain:services seat's request (comment 5270111559 on #6015). Dedup-checked before filing: no open card covers sys_email.headers_json; #8118 covers only sys_http_delivery.

Blocked-by: #8118

The gap

sys_email.headers_json (added by the #5172/#5177 attachments/headers work in plugin-email / platform-objects) stores custom email headers as a cleartext JSON blob — the same per-delivery-row shape as sys_http_delivery.headers_json, and headers can carry credentials (e.g. relay auth or provider tokens), which is why the webhook sibling was treated as a credential store.

Why blocked rather than queued

The domain:services seat's round-9 report (comment 5270111559 on #6015) records that this shape was seen and deliberately deferred: it should follow ①-b's decision, not be decided twice. #8118 carries the structural analysis (why Field.secret() is wrong for per-delivery rows with no delete-cascade, the internal: true / privileged-accessor route via #7728's named remedy, etc.) and is in flight in domain:engine-core. When #8118 lands, apply the same remedy here.

Unlock re-check (for the blocked-scan, when #8118 closes)

  1. Re-read what [security] sys_http_delivery.headers_json still stores webhook credentials in cleartext — and every services-lane shape for fixing it is structurally wrong #8118 actually landed (the remedy may be a shared mechanism that already covers sys_email — if so, close this as delivered, with the read-back as evidence).
  2. If the mechanism is per-object, this card becomes an S-sized consumer application of it: re-verify sys_email.headers_json still exists on the merged ref, then queue.

Related

#7986 (parent survey card, ①-a delivered by PR #8114) · #8118 (①-b, the structural decision carrier) · #7799 / #7728 (the fail-closed and privileged-accessor precedents).

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions