Missing user blocking is a critical safety gap under OWASP A01 (Broken Access Control) and CWE-284. Without a blocking system enforced at the query layer, a harassing user remains visible in every surface — profile, feed, search, messaging — regardless of victim intent. This is not merely a UX problem: platforms have faced regulatory scrutiny and civil liability for enabling sustained contact after victims attempted to block. Enforcement must happen at the database level; client-side filtering leaks data before it is suppressed.
Critical because the absence of query-level block enforcement means harassing users retain full visibility into and interaction capability with victims, creating direct personal safety exposure.
Create a Block table with a composite unique index on (blockerId, blockedId) and enforce the block check in every query that returns user content — profile fetches, feed queries, and search results.
// lib/db.ts
export async function getProfile(userId: string, viewerId: string) {
const isBlocked = await db.block.findFirst({
where: {
OR: [
{ blockerId: viewerId, blockedId: userId },
{ blockerId: userId, blockedId: viewerId }
]
}
})
if (isBlocked) return null
return db.user.findUnique({ where: { id: userId } })
}
Apply the same NOT IN (blocked_ids) filter to feed queries and search results. A block check that only covers profiles but not feeds gives a false sense of safety.
ID: community-social-engagement.profiles-identity.user-blocking-reporting
Severity: critical
What to look for: Enumerate all relevant files and Look for a Block or UserBlock relationship/table in the database schema. Check API endpoints for blocking users (e.g., POST /api/users/[id]/block). Verify that blocked users are globally excluded from: profile views, search results, feed visibility, and interaction capability. Look for a "Report User" feature or endpoint as well.
Pass criteria: At least 1 conforming pattern must exist. A database relationship or table for blocks exists. Blocked users are excluded from profile queries, search, and feed queries. Users cannot interact with blocked accounts (cannot see their posts, cannot follow, cannot message). Report the count of conforming instances found even on pass.
Fail criteria: No blocking mechanism exists, or blocked users are visible in search/feed/profile views, or the block status is not checked before allowing interactions.
Skip (N/A) when: The platform is internal or has no user safety concerns.
Detail on fail: "No user blocking table found in schema" or "Block relationship exists but profile queries do not check block status — blocked users are still visible"
Remediation: Implement a blocks system and enforce it across all queries:
// Prisma schema
model Block {
id String @id @default(cuid())
blockerId String
blockedId String
blocker User @relation(name: "blocker", fields: [blockerId], references: [id], onDelete: Cascade)
blocked User @relation(name: "blocked", fields: [blockedId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
@@unique([blockerId, blockedId])
}
// lib/db.ts - exclude blocks from all queries
export async function getProfile(userId: string, viewerId: string) {
const isBlocked = await db.block.findFirst({
where: {
OR: [
{ blockerId: viewerId, blockedId: userId },
{ blockerId: userId, blockedId: viewerId }
]
}
})
if (isBlocked) return null
return db.user.findUnique({ where: { id: userId } })
}
// API route for blocking
export async function POST(req: Request, { params }) {
const { blockUserId } = await req.json()
const userId = getCurrentUserId() // From auth
await db.block.create({
data: { blockerId: userId, blockedId: blockUserId }
})
return Response.json({ success: true })
}