Entry and exit conditions are explicit
Why it matters
Duplicate enrollment — calling enrollContact() twice for the same contact and sequence — creates two active send threads. Both threads advance independently and both send on their own schedules, so a single contact can receive every sequence email twice. CWE-841 (Improper Enforcement of Behavioral Workflow) applies directly: the system fails to enforce that a contact occupies exactly one position in a sequence at a time. The exit-conditions gap is equally damaging: contacts who unsubscribe mid-sequence continue receiving steps because no exit path was wired to the opt-out signal, creating CAN-SPAM and GDPR Art-6 exposure for marketing emails sent after a withdrawal of consent.
Severity rationale
High because missing deduplication causes duplicate send threads, and missing exit conditions continue sending to contacts who have unsubscribed — both are legally and reputationally damaging.
Remediation
Add an idempotency guard on enrollment and explicit exit handlers for every termination reason. In src/lib/sequences/enrollment.ts (or equivalent):
async function enrollContact(contactId: string, sequenceId: string) {
const existing = await db.contactSequence.findFirst({
where: { contactId, sequenceId, status: { in: ['active', 'paused'] } }
})
if (existing) return { alreadyEnrolled: true }
return db.contactSequence.create({
data: { contactId, sequenceId, currentStepIndex: 0, status: 'active' }
})
}
async function exitContact(
contactId: string,
sequenceId: string,
reason: 'replied' | 'opted_out' | 'manual' | 'completed'
) {
await db.contactSequence.updateMany({
where: { contactId, sequenceId, status: { in: ['active', 'paused'] } },
data: { status: reason === 'completed' ? 'completed' : reason, exitedAt: new Date() }
})
await cancelPendingSteps(contactId, sequenceId)
}
At minimum, three exit reasons must be wired: completion, opt-out, and reply.
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 Campaign Orchestration & Sequencing Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-841 — Improper Enforcement of Behavioral Workflow
- iso-25010:2011 · reliability.fault-tolerance
Taxons
History
- 2026-04-18·v1.0.0·Initial import from campaign-orchestration-sequencing·automated