Tenant creation endpoints with no rate limiting and application-only slug uniqueness checks are vulnerable to two distinct attacks: bulk tenant creation to exhaust system resources or claim desirable slug namespaces (CWE-770), and concurrent-request slug duplication that bypasses the select-then-insert uniqueness check (CWE-20, OWASP A04). In freemium SaaS products, unthrottled tenant creation is also a primary spam and abuse vector that inflates billing, corrupts benchmark data, and degrades performance for legitimate tenants.
Low because the impact is resource exhaustion and namespace pollution rather than direct data exposure, but slug duplication via race condition can corrupt routing and break tenant isolation.
Enforce slug uniqueness at the database level and add a per-user rate limit on tenant creation:
// schema.prisma — database-enforced unique constraint
model Organization {
slug String @unique
}
// src/app/api/orgs/route.ts — rate limit tenant creation per user
const ratelimit = new Ratelimit({
redis,
limiter: Ratelimit.fixedWindow(3, '1 d')
})
const { success } = await ratelimit.limit(`create-org:${session.user.id}`)
if (!success) return new Response('Too many organizations created today', { status: 429 })
The @unique constraint eliminates the race condition — the database rejects a duplicate slug with a constraint violation, which you catch and return as a 409 Conflict. Never rely on a prior SELECT check for uniqueness when concurrent inserts are possible.
ID: saas-multi-tenancy.tenant-management.tenant-creation-validated
Severity: low
What to look for: Examine the tenant creation flow — the endpoint or form where a new organization/team/workspace is created. Check for: (a) input validation on tenant name and slug (length limits, character restrictions, profanity/reserved word checks), (b) uniqueness enforcement on slugs, (c) rate limiting on tenant creation per user account, and (d) any abuse prevention for bulk tenant creation.
Pass criteria: Count all tenant creation paths. Tenant creation validates and sanitizes name and slug inputs with at least 1 validation rule. Slug uniqueness is enforced at the database level (unique index) not just application level. Tenant creation is rate-limited or requires email verification to prevent bulk abuse.
Fail criteria: No validation on tenant name or slug beyond basic presence checks. Slug uniqueness enforced only in application code (not at DB level), creating a race condition. No rate limiting on tenant creation, allowing a single user to create unlimited tenants.
Skip (N/A) when: No self-service tenant creation flow is detected (e.g., organizations are created only by platform admins). Signal: no organization/team creation form or API endpoint accessible to regular users.
Detail on fail: Example: "POST /api/orgs creates organizations with no rate limiting. Slug uniqueness check in src/app/api/orgs/route.ts uses a select-then-insert pattern without database unique constraint, allowing duplicate slugs under concurrent requests."
Remediation: Add database-level constraints and rate limiting:
// schema.prisma
model Organization {
slug String @unique // database-enforced uniqueness
}
// Rate limit tenant creation per user
const ratelimit = new Ratelimit({ redis, limiter: Ratelimit.fixedWindow(3, '1 d') })
const { success } = await ratelimit.limit(`create-org:${session.user.id}`)
if (!success) return new Response('Too many organizations created', { status: 429 })