Individual posts carry independent visibility, enforced server-side
Why it matters
Profile-level privacy settings are a coarse control — users frequently want to share a public post while keeping their overall profile private, or archive a sensitive post while keeping their profile public. Without per-post visibility, every privacy decision is all-or-nothing. More critically, feed and search APIs that check profile visibility but not post visibility will surface restricted posts to anyone who queries the endpoint with a known user ID, violating GDPR Art. 25's data minimization principle (OWASP A01:2021).
Severity rationale
Medium because the exposure is limited to posts on profiles that are public but contain individually-restricted content, but the bypass is trivially achieved through a direct API call.
Remediation
Add a visibility column to the posts table and filter on it in every feed, timeline, and search query — not just in the profile access check. In src/app/api/posts/route.ts or your ORM query layer:
ALTER TABLE posts ADD COLUMN visibility VARCHAR(20)
CHECK (visibility IN ('public', 'friends_only', 'private')) DEFAULT 'public';
Update feed queries to apply both profile and post visibility:
const posts = await db.post.findMany({
where: {
AND: [
{ visibility: 'public' },
{ author: { profile_visibility: { not: 'private' } } }
]
}
});
Search indices must also be filtered — re-indexing after adding the column is required if you use Elasticsearch or Algolia.
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 Community Privacy & Controls Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-285 — Improper Authorization
- owasp:2021 · A01 — Broken Access Control
- gdpr · Art. 25 — Data protection by design and by default
- nist:rev5 · AC-3 — Access Enforcement
Taxons
History
- 2026-04-18·v1.0.0·Initial import from community-privacy-controls·automated