Skip to content

Commit 58986ff

Browse files
committed
Update CONVENTIONS.md
1 parent d30847e commit 58986ff

File tree

1 file changed

+33
-0
lines changed

1 file changed

+33
-0
lines changed

CONVENTIONS.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,39 @@ try {
783783
}
784784
```
785785

786+
### Security: Masking 401/403 with 404
787+
788+
**Security Best Practice:** To prevent information disclosure, the backend typically returns `404 Not Found` instead of `401 Unauthorized` or `403 Forbidden` when a user lacks access to a resource.
789+
790+
**Why?**
791+
- `401`/`403` reveals that the resource exists but you can't access it
792+
- Attackers can enumerate which resources exist by observing status codes
793+
- `404` is ambiguous - resource may not exist OR you lack permission
794+
795+
**Implementation:**
796+
797+
```typescript
798+
// ✅ Backend returns 404 for unauthorized access
799+
GET /api/accounts/secret-account-id
800+
404 Not Found (even if account exists but user lacks access)
801+
802+
// ✅ Frontend treats both as "not found" for UX
803+
if (error.status === 404) {
804+
showMessage("Account not found");
805+
// User cannot distinguish between "doesn't exist" and "no permission"
806+
}
807+
808+
// ❌ Don't expose different messages for 401/403
809+
if (error.status === 403) {
810+
showMessage("Access denied"); // Leaks that resource exists!
811+
}
812+
```
813+
814+
**Exceptions:**
815+
- Authentication endpoints (login/logout) can use `401` appropriately
816+
- Admin dashboards where security is less critical
817+
- When explicitly documented as acceptable
818+
786819
---
787820

788821
## TestID Patterns

0 commit comments

Comments
 (0)