1121 lines
34 KiB
Markdown
1121 lines
34 KiB
Markdown
# Manual Security Testing Checklist
|
|
|
|
**Purpose:** Verify IDOR vulnerability fixes and authorization controls in production/staging environment
|
|
**Date Created:** 2025-12-29
|
|
**Last Updated:** 2026-01-09
|
|
**Audit Reference:** SECURITY_AUDIT_SUMMARY_2025-12-28.md, SECURITY_AUDIT_PRESENCE_2026-01-09.md
|
|
|
|
---
|
|
|
|
## Latest Test Results (2026-03-23)
|
|
|
|
### AccountInfoModal IDOR & Reports Arbitrary File Write — Fixes Applied
|
|
**Date Tested:** 2026-03-23
|
|
**Tester:** Claude Code Security Analysis
|
|
**Files Fixed:**
|
|
- `app/Http/Livewire/AccountInfoModal.php`
|
|
- `app/Http/Livewire/Reports.php`
|
|
|
|
**Vulnerabilities Found and Fixed:**
|
|
|
|
**HIGH — AccountInfoModal IDOR (Balance Disclosure)**
|
|
- `loadAccounts()` trusted `session('activeProfileId')` without ownership verification
|
|
- **Fix:** Added `ProfileAuthorizationHelper::authorize($profile)` after profile resolution in `loadAccounts()`
|
|
- Session manipulation to a victim's profile ID now results in HTTP 403
|
|
|
|
**MEDIUM — Reports Arbitrary File Write**
|
|
- `exportPdfWithChart()` and `exportPdfWithCharts()` decoded base64 data and wrote it to `storage/app/temp/` with no content validation or authentication check
|
|
- **Fix 1:** Added `abort_unless(Auth::check(), 403)` at the top of both export methods
|
|
- **Fix 2:** Added `decodeChartImage()` helper that validates magic bytes — rejects anything that is not a PNG (`\x89PNG`) or JPEG (`\xFF\xD8\xFF`); uses `base64_decode(..., strict: true)` to reject malformed input
|
|
- Rejected payloads are logged with `Log::warning` including profile context
|
|
|
|
**Results:**
|
|
- ✅ All IDOR protections from January 2026 remain intact
|
|
- ✅ AccountInfoModal now enforces ProfileAuthorizationHelper on open
|
|
- ✅ Reports chart upload now requires authentication and validates image magic bytes
|
|
- ✅ ExportProfileData authorization confirmed correct (regression tests added as Category 13)
|
|
|
|
**Status:** **APPROVED FOR PRODUCTION** ✅
|
|
|
|
**See prior report:** [SECURITY_AUDIT_PRESENCE_2026-01-09.md](/SECURITY_AUDIT_PRESENCE_2026-01-09.md)
|
|
|
|
---
|
|
|
|
## Test Results (2026-01-09)
|
|
|
|
### Presence System & Profile Status Badges
|
|
**Date Tested:** 2026-01-09
|
|
**Tester:** Claude Code Security Analysis
|
|
**Commits Tested:** 177f56ec, 9d69c337
|
|
|
|
**Results:**
|
|
- ✅ All IDOR protections from December 2025 remain intact
|
|
- ✅ ProfileAuthorizationHelper still enforced in WireChat components
|
|
- ✅ Cross-guard attacks prevented
|
|
- ✅ Session manipulation attacks blocked
|
|
- ⚠️ Profile presence is publicly visible (by design, not a vulnerability)
|
|
- ✅ All 13 WireChat security tests passing (4 tests fixed on 2026-01-09)
|
|
|
|
**Status:** **APPROVED FOR PRODUCTION** ✅
|
|
|
|
**Test Fixes Applied:**
|
|
- Fixed session initialization in 4 failing tests
|
|
- All WireChatMultiAuthTest tests now passing (13/13)
|
|
- Tests verify unauthorized conversation access is properly blocked
|
|
|
|
**See full report:** [SECURITY_AUDIT_PRESENCE_2026-01-09.md](/SECURITY_AUDIT_PRESENCE_2026-01-09.md)
|
|
|
|
---
|
|
|
|
## Prerequisites
|
|
|
|
- [x] Deploy all security fixes to staging/test environment
|
|
- [x] Have access to browser DevTools (Chrome/Firefox)
|
|
- [x] Have at least 3 test accounts created:
|
|
- [x] User A (regular user account)
|
|
- [x] User B (regular user account - victim)
|
|
- [x] Organization A (with User A as member)
|
|
- [x] Organization B (separate organization)
|
|
- [x] Bank A (optional - for bank testing)
|
|
|
|
## Session Manipulation Methods
|
|
|
|
All tests requiring session manipulation can use **either** of these methods:
|
|
|
|
**Method 1: Browser DevTools (Manual)**
|
|
- Open Browser DevTools → Application → Session Storage
|
|
- Locate and modify `activeProfileId` and `activeProfileType` keys
|
|
- Refresh the page to apply changes
|
|
|
|
**Method 2: PHP Script (Automated)**
|
|
```bash
|
|
php manipulate-session.php <profile_id> <type>
|
|
|
|
# Examples:
|
|
php manipulate-session.php 5196 user # Switch to User B
|
|
php manipulate-session.php 77 org # Switch to Organization 77
|
|
php manipulate-session.php 1 bank # Switch to Bank A
|
|
php manipulate-session.php 5195 user # Reset to User A
|
|
```
|
|
|
|
**Important:** Always refresh your browser after using the script method.
|
|
|
|
---
|
|
|
|
## Test Category 1: Profile Deletion Authorization
|
|
|
|
### Test 1.1: Unauthorized User Profile Deletion
|
|
**Risk Level:** CRITICAL
|
|
**Attack Vector:** Session manipulation to delete another user's profile
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Note User A's profile ID (check URL or DevTools)
|
|
3. [x] Navigate to Settings → Delete Account page
|
|
4. [x] Use session manipulation to switch to User B:
|
|
- **Method 1:** Open Browser DevTools → Application → Session Storage → Change `activeProfileId` value to User B's ID
|
|
- **Method 2:** Run script: `php manipulate-session.php 5196 user`
|
|
5. [x] Refresh browser (if using script method)
|
|
6. [x] Attempt to delete the profile
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden error
|
|
**Security Failure:** ❌ Profile deletion succeeds
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Log Verification:**
|
|
```bash
|
|
tail -f storage/logs/laravel.log | grep "ProfileAuthorizationHelper"
|
|
```
|
|
Should show: "Unauthorized User access attempt"
|
|
|
|
---
|
|
|
|
### Test 1.2: Unauthorized Organization Profile Deletion
|
|
**Risk Level:** CRITICAL
|
|
**Attack Vector:** Cross-organization profile deletion
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A (member of Organization A)
|
|
2. [x] Switch to Organization A profile
|
|
3. [x] Note Organization A's ID
|
|
4. [x] Use session manipulation to switch to Organization B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to Organization B's ID and `activeProfileType` to `App\Models\Organization`
|
|
- **Method 2:** Run script: `php manipulate-session.php <org_b_id> org`
|
|
5. [x] Refresh browser (if using script method)
|
|
6. [x] Navigate to organization settings → Delete Account
|
|
7. [x] Attempt deletion
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ Organization B deleted
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user # Reset to User A
|
|
```
|
|
|
|
---
|
|
|
|
### Test 1.3: Legitimate Profile Deletion (Control Test)
|
|
**Purpose:** Verify legitimate operations still work
|
|
|
|
**Steps:**
|
|
1. [ ] Login as User A
|
|
2. [ ] Navigate to Settings → Delete Account
|
|
3. [ ] Do NOT manipulate session
|
|
4. [ ] Complete deletion process
|
|
|
|
**Expected Result:** ✅ Profile deletion succeeds
|
|
**Security Failure:** ❌ Legitimate deletion blocked
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
---
|
|
|
|
## Test Category 2: Profile Modification Authorization
|
|
|
|
### Test 2.1: Unauthorized Profile Settings Modification
|
|
**Risk Level:** CRITICAL
|
|
**Attack Vector:** Session manipulation to modify another user's settings
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Navigate to profile settings page
|
|
3. [x] Use session manipulation to switch to User B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to User B's ID
|
|
- **Method 2:** Run script: `php manipulate-session.php 5196 user`
|
|
4. [x] Refresh browser (if using script method)
|
|
5. [x] Attempt to modify profile details (name, email, about, etc.)
|
|
6. [x] Click Save
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's profile modified
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 2.2: Unauthorized Organization Settings Modification
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Switch to Organization A
|
|
3. [x] Use session manipulation to switch to Organization B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to Organization B's ID
|
|
- **Method 2:** Run script: `php manipulate-session.php <org_b_id> org`
|
|
4. [x] Refresh browser (if using script method)
|
|
5. [x] Navigate to organization settings
|
|
6. [x] Attempt to modify organization details
|
|
7. [x] Click Save
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ Organization B modified
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 2.3: Unauthorized Bank Settings Modification
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. [ ] Login as User A (bank manager of Bank A)
|
|
2. [ ] Switch to Bank A profile
|
|
3. [ ] Use session manipulation to switch to Bank B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to Bank B's ID
|
|
- **Method 2:** Run script: `php manipulate-session.php <bank_b_id> bank`
|
|
4. [ ] Refresh browser (if using script method)
|
|
5. [ ] Navigate to bank settings
|
|
6. [ ] Attempt modifications
|
|
7. [ ] Click Save
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ Bank B modified
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 3: Message Settings Authorization
|
|
|
|
### Test 3.1: Unauthorized Message Settings Access
|
|
**Risk Level:** CRITICAL
|
|
**IDOR Fix:** UpdateMessageSettingsForm.php lines 34, 80
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Navigate to Settings → Message Settings
|
|
3. [x] Note current notification preferences
|
|
4. [x] Use session manipulation to switch to User B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to User B's ID
|
|
- **Method 2:** Run script: `php manipulate-session.php 5196 user`
|
|
5. [x] Refresh browser (if using script method)
|
|
6. [x] Toggle notification settings (email, push, etc.)
|
|
7. [x] Click Save
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's message settings changed
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 3.2: Organization Message Settings
|
|
**Risk Level:** HIGH
|
|
|
|
**Steps:**
|
|
1. [ ] Login as Organization A
|
|
2. [ ] Use session manipulation to switch to Organization B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to Organization B
|
|
- **Method 2:** Run script: `php manipulate-session.php <org_b_id> org`
|
|
3. [ ] Refresh browser (if using script method)
|
|
4. [ ] Navigate to message settings
|
|
5. [ ] Attempt to modify settings
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 4: Chat/Conversation Authorization (WireChat)
|
|
|
|
### Test 4.1: Unauthorized Message Sending (Session Manipulation)
|
|
**Risk Level:** CRITICAL
|
|
**Component:** WireChat/Chat/Chat.php
|
|
**Attack Vector:** Session manipulation to send messages as another user
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A (ID: 5195)
|
|
2. [x] Create or open a chat conversation
|
|
3. [x] Note the current conversation
|
|
4. [x] Use session manipulation to switch to User B (ID: 161):
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to `161`
|
|
- **Method 2:** Run script: `php manipulate-session.php 161 user`
|
|
5. [x] Refresh browser (if using script method)
|
|
6. [x] Attempt to send a message in the chat
|
|
7. [x] Click Send
|
|
|
|
**Expected Result:** ✅ User-friendly 403 error page OR "Unauthorized access" toast notification
|
|
**Security Failure:** ❌ Message sent successfully as User B
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 4.2: Unauthorized Conversation Deletion (Session Manipulation)
|
|
**Risk Level:** CRITICAL
|
|
**Component:** WireChat/Chat/Chat.php - deleteConversation()
|
|
**Attack Vector:** Session manipulation to delete another user's conversation
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Open any active chat conversation
|
|
3. [x] Use session manipulation to switch to User B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to User B's ID
|
|
- **Method 2:** Run script: `php manipulate-session.php 161 user`
|
|
4. [x] Refresh browser (if using script method)
|
|
5. [x] Click on conversation options/menu
|
|
6. [x] Click "Delete Conversation"
|
|
7. [x] Confirm deletion
|
|
|
|
**Expected Result:** ✅ User-friendly 403 error page displayed (no raw exception)
|
|
**Security Failure:** ❌ Conversation deleted successfully OR raw Symfony exception shown
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 4.3: Unauthorized Conversation Clear History (Session Manipulation)
|
|
**Risk Level:** HIGH
|
|
**Component:** WireChat/Chat/Chat.php - clearConversation()
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Open any conversation with message history
|
|
3. [x] Use session manipulation to switch to User B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to User B
|
|
- **Method 2:** Run script: `php manipulate-session.php 161 user`
|
|
4. [x] Refresh browser (if using script method)
|
|
5. [x] Click "Clear Chat History" option
|
|
6. [x] Confirm action
|
|
|
|
**Expected Result:** ✅ User-friendly 403 error page (no raw exception)
|
|
**Security Failure:** ❌ Chat history cleared OR raw exception
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 4.4: Unauthorized Message Deletion (Session Manipulation)
|
|
**Risk Level:** HIGH
|
|
**Component:** WireChat/Chat/Chat.php - deleteForMe(), deleteForEveryone()
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Open a conversation with messages
|
|
3. [x] Use session manipulation to switch to User B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to User B
|
|
- **Method 2:** Run script: `php manipulate-session.php 161 user`
|
|
4. [x] Refresh browser (if using script method)
|
|
5. [x] Right-click on any message
|
|
6. [x] Click "Delete for me" OR "Delete for everyone"
|
|
7. [x] Confirm deletion
|
|
|
|
**Expected Result:** ✅ User-friendly 403 error page (no raw exception)
|
|
**Security Failure:** ❌ Message deleted OR raw exception
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 4.5: Unauthorized New Conversation Creation (Session Manipulation)
|
|
**Risk Level:** HIGH
|
|
**Component:** WireChat/New/Chat.php - createConversation()
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Navigate to new chat/conversation page
|
|
3. [x] Use session manipulation to switch to User B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to User B
|
|
- **Method 2:** Run script: `php manipulate-session.php 161 user`
|
|
4. [x] Refresh browser (if using script method)
|
|
5. [x] Select a user to start conversation with
|
|
6. [x] Click "Start Conversation" or similar button
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden error
|
|
**Security Failure:** ❌ Conversation created as User B
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 4.6: Unauthorized Conversation List Access (Session Manipulation)
|
|
**Risk Level:** HIGH
|
|
**Component:** WireChat/Chats/Chats.php - render()
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Navigate to conversations/chats list page
|
|
3. [x] Use session manipulation to switch to User B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to User B
|
|
- **Method 2:** Run script: `php manipulate-session.php 161 user`
|
|
4. [x] Refresh the page
|
|
|
|
**Expected Result:** ✅ User-friendly 403 error page OR unauthorized component view displayed
|
|
**Security Failure:** ❌ User B's conversations visible OR raw exception
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 4.7: Cross-Organization Chat Access
|
|
**Risk Level:** HIGH
|
|
|
|
**Steps:**
|
|
1. [ ] Create conversation between Organization B and User C
|
|
2. [ ] Note conversation ID
|
|
3. [ ] Login as User A (member of Organization A)
|
|
4. [ ] Switch to Organization A profile
|
|
5. [ ] Try to access Organization B's conversation URL directly
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden or unauthorized view
|
|
**Security Failure:** ❌ Can view Organization B's conversation
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
---
|
|
|
|
### Test 4.8: Disappearing Messages Settings (Multi-Guard)
|
|
**Risk Level:** MEDIUM
|
|
**Test:** Organization/Bank/Admin can access their own conversations
|
|
|
|
**Steps:**
|
|
1. [ ] Login as Organization A
|
|
2. [ ] Create conversation with User A
|
|
3. [ ] Access disappearing messages settings
|
|
4. [ ] Verify settings page loads correctly
|
|
|
|
**Expected Result:** ✅ Page loads, settings accessible
|
|
**Security Failure:** ❌ 403 error or "null" errors
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
**Repeat for:**
|
|
- [ ] Bank profile
|
|
- [ ] Admin profile
|
|
|
|
---
|
|
|
|
### Test 4.9: Chat Actions While Session Manipulated (Comprehensive)
|
|
**Risk Level:** CRITICAL
|
|
**Purpose:** Test all chat actions fail gracefully with session manipulation
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Open an active conversation
|
|
3. [x] Use session manipulation to switch to User B:
|
|
- Run script: `php manipulate-session.php 161 user`
|
|
4. [x] Refresh browser
|
|
5. [x] Within the manipulated session, attempt ALL of the following:
|
|
- [x] Send a text message
|
|
- [ ] Send a like/reaction
|
|
- [ ] Reply to a message
|
|
- [ ] Keep a message (mark as kept from auto-deletion)
|
|
- [ ] Exit conversation
|
|
- [x] Delete a message for yourself
|
|
- [x] Delete a message for everyone
|
|
- [x] Clear conversation history
|
|
- [x] Delete entire conversation
|
|
|
|
**Expected Result:** ✅ All actions show user-friendly 403 error page (NO raw Symfony exceptions)
|
|
**Security Failure:** ❌ Any action succeeds OR any raw exception displayed
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
**Notes on Error Display:**
|
|
- Main page navigation: Should show styled 403 error page with "Logout and Reset Session" button
|
|
- Within chat component: Should show clean "Unauthorized Access" message (no stack trace)
|
|
- No red Whoops/Symfony debug pages should appear
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 5: Transaction/Payment Authorization
|
|
|
|
### Test 5.1: Unauthorized Transaction Viewing
|
|
**Risk Level:** HIGH
|
|
|
|
**Steps:**
|
|
1. [x] User B creates transaction with User C
|
|
2. [x] Note transaction ID
|
|
3. [x] Login as User A
|
|
4. [x] Navigate to `/transaction/{transaction_id}`
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User A can view transaction
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
---
|
|
|
|
### Test 5.2: Session Manipulation for Transaction Access
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Use session manipulation to switch to User B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to User B
|
|
- **Method 2:** Run script: `php manipulate-session.php 5196 user`
|
|
3. [x] Refresh browser (if using script method)
|
|
4. [x] Navigate to Transactions page
|
|
5. [x] Check which transactions are visible
|
|
|
|
**Expected Result:** ✅ Only User A's transactions visible (or 403 error)
|
|
**Security Failure:** ❌ User B's transactions visible
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 5.3: Cross-Guard Payment Attempt
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A (web guard)
|
|
2. [x] Use session manipulation to switch to Organization A:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to Organization A's ID and `activeProfileType` to `App\Models\Organization`
|
|
- **Method 2:** Run script: `php manipulate-session.php <org_a_id> org`
|
|
3. [x] Refresh browser (if using script method)
|
|
4. [x] Navigate to payment page
|
|
5. [x] Attempt to make payment from Organization A's account
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden (guard mismatch blocked)
|
|
**Security Failure:** ❌ Payment succeeds
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 6: Admin/Log Viewer Authorization
|
|
|
|
### Test 6.1: Admin Log Viewer Access
|
|
**Risk Level:** HIGH
|
|
**Components:** Admin/Log.php, Admin/LogViewer.php
|
|
|
|
**Steps:**
|
|
1. [x] Login as regular User A (NOT admin)
|
|
2. [x] Try to access admin log viewer URL directly
|
|
3. [x] Use session manipulation to switch to Admin profile:
|
|
- **Method 1:** Open DevTools → Session Storage → Change session to Admin profile
|
|
- **Method 2:** Run script: `php manipulate-session.php <admin_id> admin`
|
|
4. [x] Refresh browser (if using script method)
|
|
5. [x] Try to access logs again
|
|
|
|
**Expected Result:** ✅ Access denied for non-admin
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 7: Profile Switching
|
|
|
|
### Test 7.1: Legitimate Profile Switching
|
|
**Purpose:** Verify multi-profile system still works
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A (member of Organization A)
|
|
2. [x] Use profile switcher to switch to Organization A
|
|
3. [x] Verify profile switch succeeds
|
|
4. [x] Verify session variables updated correctly
|
|
5. [x] Perform legitimate actions as Organization
|
|
|
|
**Expected Result:** ✅ Profile switching works correctly
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
---
|
|
|
|
### Test 7.2: Switch to Unauthorized Profile
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Use profile switcher dropdown
|
|
3. [x] Check that only authorized profiles appear
|
|
4. [x] Verify Organization B (which User A is NOT a member of) is NOT in the list
|
|
|
|
**Expected Result:** ✅ Only authorized profiles shown
|
|
**Security Failure:** ❌ Unauthorized profiles accessible
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
---
|
|
|
|
## Test Category 8: Bank-Specific Authorization
|
|
|
|
### Test 8.1: Bank Chat Creation (Email Verification)
|
|
**Fix:** BankFactory email_verified_at
|
|
|
|
**Steps:**
|
|
1. [ ] Login as Bank A
|
|
2. [ ] Attempt to create new chat conversation
|
|
3. [ ] Send message to User A
|
|
|
|
**Expected Result:** ✅ Chat creation succeeds
|
|
**Security Failure:** ❌ "You do not have permission to create chats"
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
---
|
|
|
|
### Test 8.2: Bank Account Operations
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. [ ] Login as Bank A manager
|
|
2. [ ] Use session manipulation to switch to Bank B:
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to Bank B
|
|
- **Method 2:** Run script: `php manipulate-session.php <bank_b_id> bank`
|
|
3. [ ] Refresh browser (if using script method)
|
|
4. [ ] Attempt to access bank management features
|
|
5. [ ] Try to create/remove currency
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 9: Password Changes
|
|
|
|
### Test 9.1: Unauthorized Password Change
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. [x] Login as User A
|
|
2. [x] Navigate to change password page
|
|
3. [x] Open DevTools → Session Storage → Change `activeProfileId` to User B
|
|
- **OR** use script: `php manipulate-session.php 5196 user`
|
|
4. [x] Attempt to change password
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's password changed
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
---
|
|
|
|
### Test 9.2: Unauthorized Two-Factor Authentication Management
|
|
**Risk Level:** CRITICAL
|
|
**Component:** Profile/TwoFactorAuthenticationForm.php
|
|
**Attack Vector:** Session manipulation to enable/disable 2FA on another user's account
|
|
|
|
**Steps:**
|
|
1. [x] Login as Organization 77 (or any organization profile)
|
|
2. [x] Note the organization's profile ID
|
|
3. [x] Navigate to organization settings page
|
|
4. [x] Use session manipulation to switch to User 161 (or another user profile):
|
|
- **Method 1:** Open DevTools → Session Storage → Change `activeProfileId` to `161` and `activeProfileType` to `App\Models\User`
|
|
- **Method 2:** Run script: `php manipulate-session.php 161 user`
|
|
5. [x] Refresh browser
|
|
6. [x] Scroll to Two-Factor Authentication section
|
|
7. [x] Attempt to enable two-factor authentication
|
|
8. [x] Click "Enable" button
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden error immediately
|
|
**Security Failure:** ❌ QR code and setup key displayed
|
|
**Status:** [x] PASS [ ] FAIL
|
|
|
|
**Additional Tests:**
|
|
- [ ] Attempt to disable 2FA (if target user has it enabled)
|
|
- [ ] Attempt to view recovery codes
|
|
- [ ] Attempt to regenerate recovery codes
|
|
- [x] Attempt to confirm 2FA setup
|
|
|
|
**Log Verification:**
|
|
```bash
|
|
tail -f storage/logs/laravel.log | grep "ProfileAuthorizationHelper"
|
|
```
|
|
Should show: "Unauthorized User access attempt"
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 77 org # Change back to Organization 77
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 10: Validation Error Display
|
|
|
|
### Test 10.1: Profile Form Validation Errors
|
|
**Fix:** Added error display for languages field
|
|
|
|
**Steps:**
|
|
1. [ ] Login as User A
|
|
2. [ ] Navigate to profile edit form
|
|
3. [ ] Submit form with invalid data (e.g., invalid languages selection)
|
|
4. [ ] Verify validation errors display properly
|
|
|
|
**Expected Result:** ✅ Validation errors shown to user
|
|
**Security Failure:** ❌ Silent failure, no error messages
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
---
|
|
|
|
## Logging Verification Tests
|
|
|
|
### Log Test 1: Authorization Success Logging
|
|
**Steps:**
|
|
1. [ ] Perform legitimate profile modification
|
|
2. [ ] Check logs for success entry:
|
|
```bash
|
|
tail -f storage/logs/laravel.log | grep "Profile access authorized"
|
|
```
|
|
|
|
**Expected Log:**
|
|
```
|
|
[INFO] ProfileAuthorizationHelper: Profile access authorized
|
|
authenticated_user_id: {user_id}
|
|
profile_type: App\Models\User
|
|
profile_id: {user_id}
|
|
```
|
|
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
---
|
|
|
|
### Log Test 2: Authorization Failure Logging
|
|
**Steps:**
|
|
1. [ ] Attempt unauthorized access (any test above)
|
|
2. [ ] Check logs for failure entry:
|
|
```bash
|
|
tail -f storage/logs/laravel.log | grep "Unauthorized.*access attempt"
|
|
```
|
|
|
|
**Expected Log:**
|
|
```
|
|
[WARNING] ProfileAuthorizationHelper: Unauthorized {ProfileType} access attempt
|
|
authenticated_user_id: {attacker_id}
|
|
target_{profile}_id: {victim_id}
|
|
user_{profiles}: [{authorized_ids}]
|
|
```
|
|
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
---
|
|
|
|
## Browser Compatibility Testing
|
|
|
|
Test critical paths in multiple browsers:
|
|
|
|
- [ ] Chrome/Chromium (primary)
|
|
- [ ] Firefox
|
|
- [ ] Safari (if applicable)
|
|
- [ ] Edge
|
|
|
|
**Critical Paths to Test:**
|
|
1. Profile deletion with session manipulation
|
|
2. Message settings modification with session manipulation
|
|
3. Profile switching
|
|
|
|
---
|
|
|
|
## Performance Impact Assessment
|
|
|
|
### Performance Test 1: Authorization Overhead
|
|
**Steps:**
|
|
1. [ ] Time profile page load BEFORE security fixes (if possible)
|
|
2. [ ] Time profile page load AFTER security fixes
|
|
3. [ ] Calculate overhead
|
|
|
|
**Acceptable:** < 50ms additional latency
|
|
**Measured Overhead:** _____ ms
|
|
**Status:** [ ] ACCEPTABLE [ ] NEEDS OPTIMIZATION
|
|
|
|
---
|
|
|
|
### Performance Test 2: Database Query Count
|
|
**Steps:**
|
|
1. [ ] Enable query logging
|
|
2. [ ] Load profile settings page
|
|
3. [ ] Count ProfileAuthorizationHelper queries
|
|
|
|
**Tool:**
|
|
```bash
|
|
# Add to AppServiceProvider boot():
|
|
DB::listen(function($query) {
|
|
if (str_contains($query->sql, 'organizations') ||
|
|
str_contains($query->sql, 'users')) {
|
|
Log::info('Query: ' . $query->sql);
|
|
}
|
|
});
|
|
```
|
|
|
|
**Expected:** 1-2 additional queries per authorization check
|
|
**Measured:** _____ queries
|
|
**Status:** [ ] ACCEPTABLE [ ] NEEDS OPTIMIZATION
|
|
|
|
---
|
|
|
|
## Production Deployment Checklist
|
|
|
|
Before deploying to production:
|
|
|
|
- [ ] All manual tests above completed
|
|
- [ ] Critical tests (marked CRITICAL) have 100% pass rate
|
|
- [ ] Logging verified working correctly
|
|
- [ ] Performance impact acceptable
|
|
- [ ] Database backup created
|
|
- [ ] Rollback plan documented
|
|
- [ ] Monitoring alerts configured for authorization failures
|
|
|
|
---
|
|
|
|
## Post-Deployment Monitoring
|
|
|
|
**First 24 Hours:**
|
|
- [ ] Monitor logs for authorization failures spike
|
|
- [ ] Check for legitimate user access issues
|
|
- [ ] Monitor performance metrics
|
|
- [ ] Review error rate in production
|
|
|
|
**First Week:**
|
|
- [ ] Review authorization failure logs for patterns
|
|
- [ ] Investigate any repeated failures (may indicate attack attempts)
|
|
- [ ] Gather user feedback on any access issues
|
|
- [ ] Fine-tune logging if needed
|
|
|
|
**Command for Monitoring:**
|
|
```bash
|
|
# Count authorization failures per hour
|
|
tail -f storage/logs/laravel.log | grep "Unauthorized.*access attempt" | wc -l
|
|
|
|
# Alert if > 10 failures per hour (adjust threshold)
|
|
```
|
|
|
|
---
|
|
|
|
## Test Results Summary
|
|
|
|
**Date Tested:** __________________
|
|
**Tester Name:** __________________
|
|
**Environment:** [ ] Staging [ ] Production
|
|
|
|
**Overall Results:**
|
|
- Total Tests: _____
|
|
- Passed: _____
|
|
- Failed: _____
|
|
- Success Rate: _____%
|
|
|
|
**Critical Tests Status:**
|
|
- Category 1 (Profile Deletion): [ ] PASS [ ] FAIL
|
|
- Category 2 (Profile Modification): [ ] PASS [ ] FAIL
|
|
- Category 3 (Message Settings): [ ] PASS [ ] FAIL
|
|
- Category 5 (Payments): [ ] PASS [ ] FAIL
|
|
|
|
**Recommendation:**
|
|
- [ ] APPROVED for production deployment
|
|
- [ ] REQUIRES FIXES before deployment
|
|
- [ ] NEEDS FURTHER INVESTIGATION
|
|
|
|
**Notes:**
|
|
_________________________________________
|
|
_________________________________________
|
|
_________________________________________
|
|
|
|
---
|
|
|
|
## Emergency Rollback Procedure
|
|
|
|
If critical security issues found in production:
|
|
|
|
1. **Immediate:**
|
|
```bash
|
|
git revert {commit_hash}
|
|
php artisan config:clear
|
|
php artisan cache:clear
|
|
php artisan view:clear
|
|
```
|
|
|
|
2. **Communication:**
|
|
- Alert team immediately
|
|
- Document issue in detail
|
|
- Create incident report
|
|
|
|
3. **Investigation:**
|
|
- Review logs for breach indicators
|
|
- Check for unauthorized access/modifications
|
|
- Assess data integrity
|
|
|
|
---
|
|
|
|
---
|
|
|
|
## Test Category 11: AccountInfoModal — IDOR Balance Disclosure
|
|
|
|
**Added:** 2026-03-23
|
|
**Component:** `app/Http/Livewire/AccountInfoModal.php`
|
|
**Vulnerability:** `open()` calls `loadAccounts()` which trusts `session('activeProfileId')` without `ProfileAuthorizationHelper::authorize()`. Session manipulation exposes another profile's account balances.
|
|
|
|
### Test 11.1: Unauthorized User Balance Viewing
|
|
**Risk Level:** HIGH
|
|
**Attack Vector:** Session manipulation — open Account Info modal after switching to victim's profile ID
|
|
|
|
**Steps:**
|
|
1. [ ] Login as User A
|
|
2. [ ] Open Account Info modal — note your own balances
|
|
3. [ ] Manipulate session to User B:
|
|
- **Method 1:** DevTools → Session Storage → change `activeProfileId` to User B's ID
|
|
- **Method 2:** `php manipulate-session.php 5196 user`
|
|
4. [ ] Refresh browser
|
|
5. [ ] Open Account Info modal
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden OR modal shows zero/no accounts
|
|
**Security Failure:** ❌ User B's account balances visible
|
|
**Status:** [x] PASS [ ] FAIL — Fixed 2026-03-23: ProfileAuthorizationHelper::authorize() added to loadAccounts()
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 11.2: Unauthorized Organization Balance Viewing
|
|
**Risk Level:** HIGH
|
|
|
|
**Steps:**
|
|
1. [ ] Login as User A
|
|
2. [ ] Switch to an org you are NOT a member of:
|
|
- **Method 2:** `php manipulate-session.php <org_b_id> org`
|
|
3. [ ] Refresh browser
|
|
4. [ ] Open Account Info modal
|
|
|
|
**Expected Result:** ✅ HTTP 403 OR zero accounts shown
|
|
**Security Failure:** ❌ Organization B balances visible
|
|
**Status:** [x] PASS [ ] FAIL — Fixed 2026-03-23: same fix as 11.1
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 12: Reports — Arbitrary File Write
|
|
|
|
**Added:** 2026-03-23
|
|
**Component:** `app/Http/Livewire/Reports.php` — `exportPdfWithChart()`, `exportPdfWithCharts()`
|
|
**Vulnerability:** Base64 chart image data is decoded and written to `storage/app/temp/` with no MIME type or content validation.
|
|
|
|
### Test 12.1: Malformed Base64 Payload to Chart Export
|
|
**Risk Level:** MEDIUM
|
|
**Attack Vector:** Submit a PHP webshell as the chart image via a Livewire action call
|
|
|
|
**Steps:**
|
|
1. [ ] Login as User A
|
|
2. [ ] Navigate to Reports page → trigger a PDF export
|
|
3. [ ] Intercept the Livewire POST for `exportPdfWithChart` in DevTools
|
|
4. [ ] Replace the `chartImage` value with a PHP webshell in base64:
|
|
```
|
|
data:image/png;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+
|
|
```
|
|
5. [ ] Re-send the request
|
|
6. [ ] Verify `storage/app/temp/` is NOT web-accessible:
|
|
```bash
|
|
curl -I http://localhost/storage/temp/
|
|
```
|
|
|
|
**Expected Result:** ✅ Rejected (MIME validation) or written but not executable from web
|
|
**Security Failure:** ❌ File written to a web-accessible path and PHP parsed
|
|
**Status:** [x] PASS [ ] FAIL — Fixed 2026-03-23: decodeChartImage() validates PNG/JPEG magic bytes before write
|
|
|
|
---
|
|
|
|
### Test 12.2: Unauthenticated Chart Export Action
|
|
**Risk Level:** MEDIUM
|
|
|
|
**Steps:**
|
|
1. [ ] Log out
|
|
2. [ ] POST a Livewire request to `exportPdfWithChart` with a valid base64 payload
|
|
|
|
**Expected Result:** ✅ 401/403 or login redirect
|
|
**Security Failure:** ❌ File written without authentication
|
|
**Status:** [x] PASS [ ] FAIL — Fixed 2026-03-23: abort_unless(Auth::check(), 403) added to both export methods
|
|
|
|
---
|
|
|
|
## Test Category 13: ExportProfileData — Authorization Regression
|
|
|
|
**Added:** 2026-03-23
|
|
**Component:** `app/Http/Livewire/Profile/ExportProfileData.php`
|
|
**Note:** This component correctly calls `ProfileAuthorizationHelper::authorize()`. These are regression tests to verify protection stays in place.
|
|
|
|
### Test 13.1: Unauthorized Transaction Export
|
|
**Risk Level:** HIGH
|
|
|
|
**Steps:**
|
|
1. [ ] Login as User A
|
|
2. [ ] Navigate to Profile → Export Data
|
|
3. [ ] `php manipulate-session.php 5196 user`
|
|
4. [ ] Refresh browser
|
|
5. [ ] Attempt transaction export (any format)
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's transactions exported
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
**Log Verification:**
|
|
```bash
|
|
tail -f storage/logs/laravel.log | grep "ProfileAuthorizationHelper"
|
|
```
|
|
Should show: "Unauthorized User profile access attempt"
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 13.2: Unauthorized Messages Export
|
|
**Risk Level:** HIGH
|
|
|
|
**Steps:**
|
|
1. [ ] Login as User A
|
|
2. [ ] `php manipulate-session.php 5196 user`
|
|
3. [ ] Refresh browser
|
|
4. [ ] Attempt to export messages
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's private messages exported
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 13.3: Unauthorized Contacts Export
|
|
**Risk Level:** MEDIUM
|
|
|
|
**Steps:**
|
|
1. [ ] Login as User A
|
|
2. [ ] `php manipulate-session.php 5196 user`
|
|
3. [ ] Refresh browser
|
|
4. [ ] Attempt to export contacts
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's contact list exported
|
|
**Status:** [ ] PASS [ ] FAIL
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
**Document Version:** 1.2
|
|
**Last Updated:** 2026-03-23
|
|
**Next Review:** After next feature release touching profile or financial data
|