PST-023: Webhook delivery rows keep the full notification body forever and escape export and erasure #752
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#752
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found in the security audit of 2026-10-10 (
SECURITY-AUDIT-2026-10-10.md), run againstmainatc30851bfrom 8 to 10 October 2026, as PST-023. Severity: Low.The text below is the audit's entry, unchanged apart from links to the other issues it names. The finding was produced by automated review and checked by a second automated pass; re-check it before acting on it.
src/postulo/notifications/webhooks.py(61-80)Who can do it, and what they need. Not an attacker but a data-protection gap. The party affected is the account holder who deletes a webhook connection or an application, or anyone with a copy of the database or backup.
How it works.
bodyis the signed JSON text. It contains the role and company, the status-change note (free text), the offertermsand interview times.connection=NULL(on_delete=SET_NULL) and keeps the body. Deleting the application leaves its notes and offer terms in the rows. Contact erasure, retention dry-run and the account archive (core/gdpr.py, core/export.py) do not mention the table. Only deleting the whole account cascades throughowner.Impact. Offer terms, private status notes and company names persist indefinitely in plaintext in the database and in every backup after the person has deleted the connection or the record, which defeats the stated erasure and retention behaviour. Limited to the owner's own data.
Evidence.
Verification (verdict: confirmed; severity after verification: Low). Keep low. This is a privacy and retention gap, not an attacker path, and it concerns only the owner's own data. The strongest wording is that an invisible, unbounded outbox keeps free-text notes and offer terms for ever, after the user deletes the connection or the application. The receiver already had the data when the delivery was SENT, so the local body is needed only for retries. Remediation: blank or delete the body once a row is SENT or GIVEN_UP past a short window, or add webhooks to a scheduled forget_old like errands and inbox. Optionally delete deliveries when their connection or application is deleted, and list or declare the table in the archive as carried or not carried.
Suggested remediation. Prune SENT and GIVEN_UP rows after a short retention (a few days) in the scheduler pass, delete rows when their connection is deleted (CASCADE), and clear the body once it is sent. Include or explicitly name the table in the account archive and the contact-erasure and retention reports.
Fixed in
39db5cbf5on main.