feat/Update_Controllers_to_Allow_for_Premium_Membership
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
# Two-user isolation evidence
|
||||
|
||||
Captured: 2026-08-02
|
||||
|
||||
Scope: disposable local SQLite environment only. User A and User B used synthetic `@audit.invalid` identities. No production data or credentials were used.
|
||||
|
||||
## Results
|
||||
|
||||
| Resource or operation | UI level | API direct-ID test | Service/query protection | Result |
|
||||
|---|---|---|---|---|
|
||||
| Jobs | Browser blocked | A 200; B 404 for A's job; B list 0 | Explicit owner predicates and global `JobApplication` filter | Pass at API/data-query levels |
|
||||
| Companies | Browser blocked | B 404 for A's company; B list 0 | Explicit owner predicates and global `Company` filter | Pass at API/data-query levels |
|
||||
| Correspondence | Browser blocked | B list for A's job returned 0; copied ID returned 404 | Filter through owned `JobApplication` navigation | Pass at API/data-query levels |
|
||||
| Attachments | Browser blocked | A upload/list/download 200; B job access and copied attachment download 404 | Owned-job query before file operation | Pass at API/data-query levels |
|
||||
| Career Profile | Browser blocked | B's current-profile request 404 | Current-user lookup plus owner query filter | Pass at API/data-query levels |
|
||||
| CV variants | Browser blocked | Copied A variant ID returned 404, but B's own list returned 500 | Owner predicate/filter exists; list blocked by SQLite translation | Partial: protection inspected and direct ID passed; list broken |
|
||||
| Application workspace | Browser blocked | B copied A ID returned 404; A request returned 500 | Owner predicate exists; owner path blocked by SQLite translation | Partial |
|
||||
| Checklist | Browser blocked | B copied A job returned 404; A 200 | Owner predicate on job/items | Pass at API/data-query levels |
|
||||
| Timeline | Browser blocked | Both users received 500 | Ambiguous route selection occurs before authorization logic | Blocked by endpoint defect; no exposure observed |
|
||||
| Interview preparation | Browser blocked | Both users received 500 | Ambiguous route selection occurs before authorization logic | Blocked by endpoint defect; no exposure observed |
|
||||
| AI results | Browser blocked | History endpoint returned 500 | Owner predicates and query filter exist | Blocked by SQLite translation |
|
||||
| Settings/session | Browser blocked | B `/auth/me` returned only B | Identity/session-bound current user | Pass at API level |
|
||||
| Administrative operation | Browser blocked | B request returned 403 | `[Authorize(Roles = "Admin")]` | Pass at API level |
|
||||
| Email threads/provider data | External providers not connected | Local correspondence passed; provider-specific IDs not live-tested | Owner-scoped connection and correspondence queries inspected | Code-inspected/partially tested |
|
||||
|
||||
## Protection layers observed
|
||||
|
||||
- UI: protected routes require an authenticated shell, but hiding was not counted as authorization.
|
||||
- API: controllers use explicit local-auth or admin authorization attributes.
|
||||
- Service: important reads carry `OwnerUserId` or owned-parent predicates.
|
||||
- EF: global filters deny on null current user and match owner IDs.
|
||||
- Database: tenant ownership is primarily enforced in application queries; many owner columns are not foreign keys to `AspNetUsers`, so database constraints alone do not provide tenant isolation.
|
||||
|
||||
## Limitations
|
||||
|
||||
- The in-app browser control client was missing, so UI navigation as A/B was not performed.
|
||||
- Timeline/interview and several CV/AI paths failed before an ownership result could be observed.
|
||||
- No Gmail, Microsoft Graph, IMAP, Stripe, cloud AI, or remote object storage was contacted.
|
||||
|
||||
No cross-user disclosure was confirmed in the paths that returned a meaningful result.
|
||||
Reference in New Issue
Block a user