MarkWilsonsCustomerController (Domain/Customers) lists/creates/reads/updates customer PII — names, addresses, phone numbers, service history — and is gated only by a bare [Authorize]. The API's DefaultPolicy is RequireAuthenticatedUser() (Infrastructure/Authentication.cs:33), so bare [Authorize] = any authenticated user, and the handlers filter by _id only (no owner/tenant/role check).
This controller lives in the shared SpikerSoft.Api — the same instance and Keycloak realm that authenticates students, game players, art-studio and code-lesson users. So any platform account (e.g. a student) can call GET /…/customers, GET /…/customers/{id}, or PUT /…/customers/{id} and read or modify Mark Wilson's customer PII. spikersoft-issues#415 fixed the earlier anonymous-by-omission gap but only required authentication, not the staff/admin role this data warrants.
Fix (this PR)
Gate the controller with the codebase's established staff/admin pattern — [Authorize(Roles = "Admin,admin,Staff,staff")] — already used by 27 peer controllers (e.g. CacheController) and equivalent to the AdminOrStaff policy (SpikerSoftRoles.IsAdminOrStaff). Regular user-facing controllers keep bare [Authorize] (correct for them); only the staff CRM is tightened. Added MarkWilsonCustomerControllerAuthorizationTests cases asserting the role gate.
Related (same gap, NOT in this PR — needs per-controller confirmation)
The sibling generator-service CRM controllers share the identical bare-[Authorize] gap and should get the same gate after verifying none has a legitimate non-staff endpoint: ServiceCallsController, LaborsController, PartsController, MilagesController, GeneratorBrandsController, ServiceCallReasonsController.
## Vulnerability (broken access control / OWASP A01)
`MarkWilsonsCustomerController` (Domain/Customers) lists/creates/reads/updates customer PII — names, addresses, phone numbers, service history — and is gated only by a bare `[Authorize]`. The API's `DefaultPolicy` is `RequireAuthenticatedUser()` (Infrastructure/Authentication.cs:33), so bare `[Authorize]` = **any authenticated user**, and the handlers filter by `_id` only (no owner/tenant/role check).
This controller lives in the shared `SpikerSoft.Api` — the same instance and Keycloak realm that authenticates students, game players, art-studio and code-lesson users. So **any** platform account (e.g. a student) can call `GET /…/customers`, `GET /…/customers/{id}`, or `PUT /…/customers/{id}` and read or modify Mark Wilson's customer PII. spikersoft-issues#415 fixed the earlier anonymous-by-omission gap but only required *authentication*, not the staff/admin role this data warrants.
## Fix (this PR)
Gate the controller with the codebase's established staff/admin pattern — `[Authorize(Roles = "Admin,admin,Staff,staff")]` — already used by 27 peer controllers (e.g. CacheController) and equivalent to the `AdminOrStaff` policy (`SpikerSoftRoles.IsAdminOrStaff`). Regular user-facing controllers keep bare `[Authorize]` (correct for them); only the staff CRM is tightened. Added `MarkWilsonCustomerControllerAuthorizationTests` cases asserting the role gate.
## Related (same gap, NOT in this PR — needs per-controller confirmation)
The sibling generator-service CRM controllers share the identical bare-`[Authorize]` gap and should get the same gate after verifying none has a legitimate non-staff endpoint: `ServiceCallsController`, `LaborsController`, `PartsController`, `MilagesController`, `GeneratorBrandsController`, `ServiceCallReasonsController`.
Resolved in spikersoft-backend PR #385 (merged to master). Gated MarkWilsonsCustomerController to [Authorize(Roles = "Admin,admin,Staff,staff")] (the pattern 27 peer controllers use), so customer PII is no longer reachable by any authenticated non-staff account. Added a role-gate assertion test (7 pass). Sibling CRM controllers noted here for a verified follow-up. Closing.
Resolved in spikersoft-backend PR #385 (merged to `master`). Gated `MarkWilsonsCustomerController` to `[Authorize(Roles = "Admin,admin,Staff,staff")]` (the pattern 27 peer controllers use), so customer PII is no longer reachable by any authenticated non-staff account. Added a role-gate assertion test (7 pass). Sibling CRM controllers noted here for a verified follow-up. Closing.
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.
Vulnerability (broken access control / OWASP A01)
MarkWilsonsCustomerController(Domain/Customers) lists/creates/reads/updates customer PII — names, addresses, phone numbers, service history — and is gated only by a bare[Authorize]. The API'sDefaultPolicyisRequireAuthenticatedUser()(Infrastructure/Authentication.cs:33), so bare[Authorize]= any authenticated user, and the handlers filter by_idonly (no owner/tenant/role check).This controller lives in the shared
SpikerSoft.Api— the same instance and Keycloak realm that authenticates students, game players, art-studio and code-lesson users. So any platform account (e.g. a student) can callGET /…/customers,GET /…/customers/{id}, orPUT /…/customers/{id}and read or modify Mark Wilson's customer PII. spikersoft-issues#415 fixed the earlier anonymous-by-omission gap but only required authentication, not the staff/admin role this data warrants.Fix (this PR)
Gate the controller with the codebase's established staff/admin pattern —
[Authorize(Roles = "Admin,admin,Staff,staff")]— already used by 27 peer controllers (e.g. CacheController) and equivalent to theAdminOrStaffpolicy (SpikerSoftRoles.IsAdminOrStaff). Regular user-facing controllers keep bare[Authorize](correct for them); only the staff CRM is tightened. AddedMarkWilsonCustomerControllerAuthorizationTestscases asserting the role gate.Related (same gap, NOT in this PR — needs per-controller confirmation)
The sibling generator-service CRM controllers share the identical bare-
[Authorize]gap and should get the same gate after verifying none has a legitimate non-staff endpoint:ServiceCallsController,LaborsController,PartsController,MilagesController,GeneratorBrandsController,ServiceCallReasonsController.Resolved in spikersoft-backend PR #385 (merged to
master). GatedMarkWilsonsCustomerControllerto[Authorize(Roles = "Admin,admin,Staff,staff")](the pattern 27 peer controllers use), so customer PII is no longer reachable by any authenticated non-staff account. Added a role-gate assertion test (7 pass). Sibling CRM controllers noted here for a verified follow-up. Closing.