Users can permanently delete their account and all associated PII
Why it matters
GDPR Art. 17 (right to erasure), CCPA §1798.105, and LGPD Art. 18(VI) all require that users can request permanent deletion of their personal data. A soft-delete flag with no automated purge fulfills none of these obligations — the PII still exists in the database and in backups. ISO-27001:2022 A.8.10 requires documented and implemented media disposal and data deletion controls. The practical risk: a soft-deleted user's email and personal data sitting in your database is indistinguishable from active data to a database attacker or a regulatory auditor. Orphaned records in orders, activity logs, and uploaded files that reference a deleted user's ID also constitute retained PII that should have been erased.
Severity rationale
Low because the right to deletion is user-triggered rather than an automatic systemic exposure, but non-compliance with a submitted deletion request is a direct Art. 17 violation.
Remediation
Implement a two-phase deletion: immediate soft-delete that revokes access, followed by a cron-driven permanent purge after the grace period.
// Phase 1: app/api/user/delete/route.ts — immediate soft delete
export async function DELETE() {
const session = await getServerSession()
if (!session?.user?.id) return new Response('Unauthorized', { status: 401 })
await db.user.update({
where: { id: session.user.id },
data: { deletedAt: new Date(), email: null, name: 'Deleted User' }
})
return Response.json({ ok: true })
}
// Phase 2: app/api/cron/purge-deleted/route.ts — permanent purge after 30 days
export async function GET() {
const cutoff = new Date()
cutoff.setDate(cutoff.getDate() - 30)
const toDelete = await db.user.findMany({ where: { deletedAt: { lt: cutoff } }, select: { id: true } })
for (const user of toDelete) {
await db.$transaction([
db.activityLog.deleteMany({ where: { userId: user.id } }),
db.order.deleteMany({ where: { userId: user.id } }),
db.user.delete({ where: { id: user.id } }),
])
}
return Response.json({ purged: toDelete.length })
}
Add a "Delete Account" button in user settings with a confirmation modal that states what will be deleted and when the purge completes. Schedule the purge cron in vercel.json or your equivalent scheduler.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Data Protection Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- gdpr · Art. 17 — Right to erasure ('right to be forgotten')
- ccpa · §1798.105 — Consumer right to deletion of personal information
- lgpd · Art. 18(VI) — Right to deletion of personal data processed with consent
- iso-27001:2022 · A.8.10 — Information deletion
- soc2:2017 · CC6.2 — User registration, authorization, and access removal
- soc2:2017 · C1.2 — Disposal of confidential information
Taxons
History
- 2026-04-18·v1.0.0·Initial import from data-protection·automated
- 2026-07-06·v1.0.1·Add SOC 2 TSC mapping (CC6.2, C1.2) from the verified compliance crosswalk register (docs/compliance/).·by soc2-mapping-enrichment-ship-2