Problem: The endpoint accepts userId as a query parameter and loads UserActivities for that id with no parent/self check. Any authenticated caller can substitute another user's id and read their per-domain activity, including RecentActivityDto.Metadata.
Unlike GetChildKnowledgeProgressQuery which enforces parent/child linkage, this handler has no authorization gate.
Fix: Mirror the child-progress authorization model:
If userId == caller.UserId allow it
Otherwise require linked-parent relationship or a staff role
Reject with 403 otherwise
Acceptance criteria:
Self-access works
Parent-of-child access works for legitimately linked accounts
Cross-user access by unrelated users returns 403
Unit test covers all three branches
**Severity:** Critical (Security)
**File:** `SpikerSoft.Api/Domain/ActivityTracking/ActivityController.cs` (~90-100) + `GetDomainDetailQueryHandler.cs`
**Problem:** The endpoint accepts `userId` as a query parameter and loads `UserActivities` for that id with no parent/self check. Any authenticated caller can substitute another user's id and read their per-domain activity, including `RecentActivityDto.Metadata`.
Unlike `GetChildKnowledgeProgressQuery` which enforces parent/child linkage, this handler has no authorization gate.
**Fix:** Mirror the child-progress authorization model:
- If `userId == caller.UserId` allow it
- Otherwise require linked-parent relationship or a staff role
- Reject with 403 otherwise
**Acceptance criteria:**
- [ ] Self-access works
- [ ] Parent-of-child access works for legitimately linked accounts
- [ ] Cross-user access by unrelated users returns 403
- [ ] Unit test covers all three branches
**Resolved.**
Added `CallerUserId` and `BypassAuthorization` to `GetDomainDetailQuery`. The handler now:
- Allows the call when `request.UserId == request.CallerUserId` (self)
- Otherwise loads the target's `UserProfile` and verifies `ParentalControls.ParentKeycloakUserId == CallerUserId`
- Throws `UnauthorizedAccessException` (mapped to 403 by the controller) when neither check passes
- Skips the gate entirely when `BypassAuthorization == true`, set by the controller for staff/admin callers via the new `IsStaff()` helper
`ActivityController.GetDomainDetail` now passes `GetUserId()` and `IsStaff()` and catches `UnauthorizedAccessException` -> `Forbid()`.
Files changed:
- `SpikerSoft.Business/Domain/Activity/Queries/GetDomainDetail/GetDomainDetailQuery.cs`
- `SpikerSoft.Business/Domain/Activity/Queries/GetDomainDetail/GetDomainDetailQueryHandler.cs`
- `SpikerSoft.Api/Domain/ActivityTracking/ActivityController.cs`
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Severity: Critical (Security)
File:
SpikerSoft.Api/Domain/ActivityTracking/ActivityController.cs(~90-100) +GetDomainDetailQueryHandler.csProblem: The endpoint accepts
userIdas a query parameter and loadsUserActivitiesfor that id with no parent/self check. Any authenticated caller can substitute another user's id and read their per-domain activity, includingRecentActivityDto.Metadata.Unlike
GetChildKnowledgeProgressQuerywhich enforces parent/child linkage, this handler has no authorization gate.Fix: Mirror the child-progress authorization model:
userId == caller.UserIdallow itAcceptance criteria:
Resolved.
Added
CallerUserIdandBypassAuthorizationtoGetDomainDetailQuery. The handler now:request.UserId == request.CallerUserId(self)UserProfileand verifiesParentalControls.ParentKeycloakUserId == CallerUserIdUnauthorizedAccessException(mapped to 403 by the controller) when neither check passesBypassAuthorization == true, set by the controller for staff/admin callers via the newIsStaff()helperActivityController.GetDomainDetailnow passesGetUserId()andIsStaff()and catchesUnauthorizedAccessException->Forbid().Files changed:
SpikerSoft.Business/Domain/Activity/Queries/GetDomainDetail/GetDomainDetailQuery.csSpikerSoft.Business/Domain/Activity/Queries/GetDomainDetail/GetDomainDetailQueryHandler.csSpikerSoft.Api/Domain/ActivityTracking/ActivityController.cs