Files
timebank-cc-public/references/MANUAL_SECURITY_TESTING_CHECKLIST.md
Ronald Huynen 2547717edb Initial commit
2026-03-23 21:37:59 +01:00

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