Profiles without visibility controls violate GDPR Art. 25 (data protection by design) and CCPA §1798.100 (consumer right to control their data). Under OWASP A01 (Broken Access Control) and CWE-284, any user whose profile is marked private but still returned to strangers has had their consent overridden by a code defect. Beyond compliance, exposed private profiles leak follower graphs, contact hints, and behavioral patterns to scrapers and stalkers — a direct user safety failure.
High because bypassed privacy controls expose user data to unauthorized parties at query time, constituting a broken access control failure with immediate personal safety implications.
Gate every profile fetch through an access-control layer in lib/db.ts that checks the is_private flag and the viewer's follow status before returning any data. Never expose even partial profile fields to unauthorized viewers.
// lib/db.ts
export async function getUserProfile(userId: string, viewerId?: string) {
const user = await db.user.findUnique({ where: { id: userId } })
if (!user) return null
if (!user.is_private) return user
if (viewerId === userId) return user
const isFollower = await db.follow.findFirst({
where: { followingId: viewerId, followedId: userId }
})
return isFollower ? user : null
}
Also add is_private Boolean @default(false) to your Prisma User model if the field does not yet exist.
ID: community-social-engagement.profiles-identity.privacy-visibility-controls
Severity: high
What to look for: Enumerate all relevant files and Check the user schema (Prisma, Drizzle, SQL) for privacy-related fields like is_private, visibility, profile_public, or similar. Check profile query logic for access control: RLS policies in PostgreSQL, API filters that limit profile data exposure, or conditional rendering in components. Verify that private profiles are not accessible to unauthenticated or non-follower users.
Pass criteria: No more than 0 violations are acceptable. Profile visibility is controlled by a schema field (e.g., is_private: boolean). Queries fetching profiles for display apply access control filters. Private profiles are not displayed to users who haven't been granted access. Report the count of conforming instances found even on pass.
Fail criteria: No visibility controls in the schema, or profiles are returned without permission checks, or private profiles are visible to all users. A partial or incomplete implementation does not count as pass.
Skip (N/A) when: All user profiles are always public (no privacy feature implemented).
Cross-reference: For accessibility evaluation of social interaction patterns, the Accessibility Basics audit covers focus management and screen reader support.
Detail on fail: "User schema has no visibility/privacy field. All profiles are public regardless of user preference." or "Profile API returns full profile data without checking privacy status or viewer relationship"
Remediation: Implement profile visibility controls:
// Prisma schema
model User {
id String @id
name String
bio String?
is_private Boolean @default false
// ... other fields
}
// lib/db.ts - with access control
export async function getUserProfile(userId: string, viewerId?: string) {
const user = await db.user.findUnique({ where: { id: userId } })
if (!user) return null
if (!user.is_private) return user // Public profile
// Private profile: only viewer or self can see
if (viewerId === userId) return user
// Check if viewer is a follower
const isFollower = await db.follow.findFirst({
where: { followingId: viewerId, followedId: userId }
})
if (isFollower) return user
return null // Deny access
}