CMMC 2.0 IA.L1-3.5.1 (NIST 800-171r2 3.5.1) requires that users and processes are uniquely identified before system access is granted. Without a uniqueness constraint on user identifiers, two accounts can share the same identity — making it impossible to attribute actions to a specific individual. CMMC accountability requires an audit trail tied to unique principals. CWE-287 (Improper Authentication) and OWASP A07 (Identification and Authentication Failures) flag non-unique identification as a foundational authentication failure. A system that cannot distinguish between two users sharing an email cannot satisfy CMMC's accountability requirements, regardless of how well other controls are implemented.
Critical because non-unique user identifiers make individual accountability impossible — a foundational CMMC requirement that cannot be compensated by other controls.
Enforce unique identification at the database level, not just the application layer. Application-level checks can be bypassed; database constraints cannot:
// prisma/schema.prisma
model User {
id String @id @default(cuid())
email String @unique // Database-enforced — not nullable, not optional
role String @default("user")
createdAt DateTime @default(now())
}
For raw SQL migrations:
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT NOT NULL UNIQUE,
role TEXT NOT NULL DEFAULT 'user',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX idx_users_email ON users(email);
In the registration handler, catch unique-constraint violations and return a client-safe message — do not forward the raw database error, which would expose your schema and table names.
ID: gov-cmmc-level-1.identification-auth.user-identification
Severity: critical
CMMC Practice: IA.L1-3.5.1
What to look for: Examine the user model, database schema, and registration flow. Verify that each user receives a unique identifier (UUID, auto-increment ID, or email with a unique constraint). Look for database schema files (Prisma schema, Drizzle schema, SQL migrations) and confirm uniqueness constraints on the user identifier column. Check for any patterns that would allow shared or generic accounts — look for hard-coded demo users, shared test credentials committed to code, or registration flows that don't enforce unique emails. Search for any INSERT or CREATE patterns that don't enforce uniqueness.
Pass criteria: Count all user identifier fields in the database schema and verify each has a uniqueness constraint. Every user receives a unique identifier (UUID preferred, or email with a unique database constraint). At least 1 unique constraint exists on user identifiers. Report: "X user identifier fields found, Y have uniqueness constraints."
Fail criteria: No uniqueness constraint on user identifiers. Shared accounts enabled by design. Multiple users can register with the same email without error. No user model found despite the application having access control.
Skip (N/A) when: Never — unique identification is the foundation of accountability.
Detail on fail: Specify the identification gap. Example: "User schema in prisma/schema.prisma has no @unique constraint on email field. Two users can register with identical emails — impossible to identify actions by individual." Keep under 500 characters.
Remediation: Enforce unique user identification at the database level:
// prisma/schema.prisma
model User {
id String @id @default(cuid())
email String @unique // Unique constraint is non-negotiable
role String @default("user")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
For SQL migrations, add a unique index explicitly:
-- migrations/001_create_users.sql
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT NOT NULL UNIQUE,
role TEXT NOT NULL DEFAULT 'user',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX idx_users_email ON users(email);
In the registration handler, catch duplicate key errors and return an appropriate response rather than leaking database error details to the client.