GDPR Article 17 (Right to Erasure) and CCPA §1798.105 require that deletion of a user's account removes all associated personal data — not just the primary user record. CWE-459 (Incomplete Cleanup) covers exactly this pattern: a delete operation that removes the primary entity but leaves related records orphaned. AI conversation history typically contains some of the most sensitive personal data in the system — verbatim user statements about their problems, circumstances, and intentions. Orphaned conversation records after account deletion mean the user's data persists in the database indefinitely under a now-deleted user ID, violating the erasure right and potentially creating ghost data that can be queried without ownership context.
Info because cascade delete configuration is a correctness issue rather than an exploitable vulnerability, but orphaned AI data after account deletion constitutes a documented GDPR Art. 17 compliance gap.
Configure database-level cascade deletes so conversation records are automatically removed when the parent user is deleted — no application code change required for each new deletion path.
// schema.prisma
model Conversation {
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
If explicit deletion is required (e.g., audit requirements demand a logged deletion event), use a transaction in your account deletion action:
await db.$transaction([
db.message.deleteMany({ where: { conversation: { userId } } }),
db.conversation.deleteMany({ where: { userId } }),
db.user.delete({ where: { id: userId } })
])
Verify by writing an integration test: create a user, add conversations, delete the user, and assert db.conversation.count({ where: { userId } }) returns 0.
ID: ai-data-privacy.data-retention-deletion.gdpr-erasure-ai-data
Severity: info
What to look for: Enumerate every relevant item. Locate the account deletion flow — an API route or server action that deletes a user account. Examine what data it removes. Look for: explicit delete calls on conversation/message tables before deleting the user record, database cascade delete configuration (onDelete: Cascade in Prisma, ON DELETE CASCADE in SQL schema), or a documented gap where conversation records would become orphaned after user deletion.
Pass criteria: At least 1 of the following conditions is met. Account deletion either explicitly deletes conversation/AI data records, or database foreign key cascade rules are configured to automatically delete related conversation records when the parent user is deleted.
Fail criteria: Account deletion logic removes the user record but does not explicitly delete related AI conversation data, and database schema does not include cascade delete rules — leaving orphaned conversation records after the user is gone.
Skip (N/A) when: No user accounts or no persisted AI conversation data. Or conversations are stored without a user foreign key (anonymous/ephemeral sessions only).
Detail on fail: "Account deletion in [file] removes the user record but conversation/message records lack cascade delete — orphaned AI data with PII may remain after account deletion"
Remediation: "Right to Erasure" means all data about a user should be removable, including AI interaction history. The cleanest way to implement this is database-level cascade deletes.
In Prisma schema, add onDelete: Cascade to the relationship:
model Conversation {
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
If explicit deletion is preferred over cascade:
// In account deletion server action
await db.$transaction([
db.message.deleteMany({ where: { conversation: { userId } } }),
db.conversation.deleteMany({ where: { userId } }),
db.user.delete({ where: { id: userId } })
])
Verify by creating a test account, adding conversations, deleting the account, and confirming conversation records are gone.