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

599 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Admin Management Components Security Analysis
**Date:** 2025-12-31
**Scope:** Posts, Categories, Tags, Profiles, and Mailings Management
**Status:** ⚠️ PARTIAL PROTECTION - CRITICAL VULNERABILITIES FOUND
---
## Executive Summary
**STATUS: ⚠️ SECURITY GAPS IDENTIFIED**
Analysis of 5 admin management Livewire components reveals **significant authorization vulnerabilities**. While some components have basic authentication checks, **NONE of them use ProfileAuthorizationHelper** for IDOR protection, and most lack proper admin permission verification.
**Critical Finding:** Users can potentially access admin management interfaces by manipulating session variables, as authorization is checked inconsistently across components.
---
## Components Analyzed
1. **Posts/Manage.php** - Line 1364 (NO authorization checks)
2. **Categories/Manage.php** - Line 1017 (NO authorization checks)
3. **Tags/Manage.php** - Line 735 (NO authorization checks)
4. **Profiles/Manage.php** - Line 1840 (NO ProfileAuthorizationHelper)
5. **Mailings/Manage.php** - Line 1145 (Basic guard check only)
---
## Security Analysis by Component
### 1. Posts/Manage.php ❌ CRITICAL VULNERABILITY
**File:** `app/Http/Livewire/Posts/Manage.php`
**Lines:** 1-1364
**Authorization Status:****NO AUTHORIZATION CHECKS**
**Vulnerabilities:**
- **No mount() authorization** - Anyone can access the component
- **No ProfileAuthorizationHelper** usage
- **No admin permission checks**
- **No guard verification**
**Attack Scenarios:**
```php
// Attack: Regular user accesses admin post management
// 1. User authenticates as regular user on 'web' guard
// 2. User manipulates session to access admin area
// 3. User can view/edit/delete all posts system-wide
// 4. NO PROTECTION - Component allows full access
```
**Exposed Methods (All Unprotected):**
- `edit($translationId)` - Line 301 - Can edit ANY post by ID
- `save()` - Line 409 - Can modify ANY post
- `deleteSelected()` - Line 742 - Can bulk delete posts
- `undeleteSelected()` - Line 773 - Can restore posts
- `stopPublication()` - Line 884 - Can unpublish any post
- `startPublication()` - Line 912 - Can publish any post
**Impact:** CRITICAL - Complete unauthorized access to post management
---
### 2. Categories/Manage.php ❌ CRITICAL VULNERABILITY
**File:** `app/Http/Livewire/Categories/Manage.php`
**Lines:** 1-1017
**Authorization Status:****NO AUTHORIZATION CHECKS**
**Vulnerabilities:**
- **No mount() authorization** - Anyone can access
- **No ProfileAuthorizationHelper** usage
- **No admin permission checks**
- **No guard verification**
**Attack Scenarios:**
```php
// Attack: Regular user manages categories
// 1. User accesses category management without admin rights
// 2. Can view all categories and their translations
// 3. Can edit/delete categories (affecting tags system-wide)
// 4. Can create new categories
// 5. NO PROTECTION - Full category system access
```
**Exposed Methods (All Unprotected):**
- `openBulkDeleteTranslationsModal()` - Line 140
- `deleteSelected()` - Line 232 - Deletes categories with tag reassignment
- `deleteCategory()` - Line 418 - Deletes single category
- `updateCategory()` - Line 547 - Modifies categories
- `storeCategory()` - Line 682 - Creates new categories
**Impact:** CRITICAL - Unauthorized category management affects entire tag system
---
### 3. Tags/Manage.php ❌ CRITICAL VULNERABILITY
**File:** `app/Http/Livewire/Tags/Manage.php`
**Lines:** 1-735
**Authorization Status:****NO AUTHORIZATION CHECKS**
**Vulnerabilities:**
- **No mount() authorization** - Anyone can access
- **No ProfileAuthorizationHelper** usage
- **No admin permission checks**
- **No guard verification**
**Attack Scenarios:**
```php
// Attack: Regular user manages tags
// 1. User accesses tag management interface
// 2. Can view all tags with user counts
// 3. Can edit tags (affecting all profiles using them)
// 4. Can merge tags (changing profile tags globally)
// 5. Can delete tags (removing skills from profiles)
// 6. NO PROTECTION - Complete tag system access
```
**Exposed Methods (All Unprotected):**
- `openDeleteTagModal($tagId)` - Line 124
- `deleteTag()` - Line 320 - Deletes tags
- `openBulkDeleteTagsModal()` - Line 137
- `deleteSelected()` - Line 353 - Bulk deletes tags
- `openEditTagModal($tagId)` - Line 193
- `updateTag()` - Line 453 - Modifies/merges tags (affects ALL profiles)
**Special Concern - Tag Merging:**
```php
// Line 461-479: Tag merging without authorization
// This affects ALL profiles that have the merged tag
DB::table('taggable_taggables')
->where('tag_id', $this->selectedTagId)
->update(['tag_id' => $mergeTagId]);
```
**Impact:** CRITICAL - Tag modifications affect all user profiles system-wide
---
### 4. Profiles/Manage.php ⚠️ INSUFFICIENT PROTECTION
**File:** `app/Http/Livewire/Profiles/Manage.php`
**Lines:** 1-1840
**Authorization Status:** ⚠️ **BASIC CHECK ONLY - NO IDOR PROTECTION**
**Current Protection (Lines 96-102):**
```php
public function mount()
{
// Check authorization
if (!Auth::guard('admin')->check() && !Auth::guard('bank')->check()) {
abort(403, __('Unauthorized to access mailings management.'));
}
// ... initialization code
}
```
**Vulnerabilities:**
- ✅ Has basic guard check in mount()
-**No ProfileAuthorizationHelper** usage
-**No verification** that admin accessing their own admin profile
-**Allows Bank level=1 to access** (not restricted to level=0 central bank)
**Attack Scenarios:**
```php
// Attack 1: Cross-guard attack (similar to ExportProfileData issue)
// 1. User authenticated on 'web' guard
// 2. User IS a manager of Bank ID 1
// 3. User manipulates session to active Bank profile
// 4. mount() check PASSES (Bank guard exists)
// 5. But user is on WRONG GUARD (web instead of bank)
// 6. Can access profile management as if they were Bank
// Result: Unauthorized access to profile management
// Attack 2: Bank level 1 accessing admin functions
// 1. Bank level 1 authenticates on 'bank' guard
// 2. mount() check PASSES (Bank guard exists)
// 3. Bank level 1 shouldn't have admin access
// Result: Non-central banks can manage all profiles
```
**Exposed Methods (Insufficient Protection):**
- `openEditAccountsModal($profileId, $modelName)` - Line 216
- `openEditProfileModal($profileId, $modelName)` - Line 258
- `updateProfile()` - Line 631 - Can edit ANY profile
- `deleteProfile()` - Line 1386 - Can delete profiles
- `restoreProfile()` - Line 1493 - Can restore deleted profiles
**Missing Validation:**
- No check that admin is acting on behalf of their own Admin profile
- No verification of cross-guard attacks
- No restriction for Bank level (should be level=0 only)
**Impact:** HIGH - Partial protection but vulnerable to guard manipulation
---
### 5. Mailings/Manage.php ⚠️ INSUFFICIENT PROTECTION
**File:** `app/Http/Livewire/Mailings/Manage.php`
**Lines:** 1-1145
**Authorization Status:** ⚠️ **BASIC CHECK ONLY - NO IDOR PROTECTION**
**Current Protection (Lines 96-102):**
```php
public function mount()
{
// Check authorization
if (!Auth::guard('admin')->check() && !Auth::guard('bank')->check()) {
abort(403, __('Unauthorized to access mailings management.'));
}
$this->estimatedRecipientCount = 0;
}
```
**Vulnerabilities:**
- ✅ Has basic guard check in mount()
-**No ProfileAuthorizationHelper** usage
-**No verification** of cross-guard attacks
-**Allows Bank access** without level verification
**Attack Scenarios:**
```php
// Attack: Cross-guard mailing access
// 1. User authenticated on 'web' guard
// 2. User is manager of Bank ID 1
// 3. User manipulates session: activeProfileType = Bank, activeProfileId = 1
// 4. mount() check PASSES because Bank guard exists
// 5. User on WRONG GUARD accesses mailing management
// Result: Unauthorized mailing access
```
**Exposed Methods (Insufficient Protection):**
- `openCreateModal()` - Line 163
- `openEditModal($mailingId)` - Line 170
- `saveMailing()` - Line 418 - Creates/updates mailings
- `deleteMailing($mailingId)` - Line 485
- `sendMailing()` - Line 527 - Sends emails to users
- `sendTestMail($mailingId)` - Line 611
**Missing Validation:**
- No cross-guard attack prevention
- No admin profile ownership verification
- Bank access not restricted to central bank only
**Impact:** HIGH - Can create/send mass mailings without proper authorization
---
## Common Vulnerabilities Across All Components
### 1. Missing ProfileAuthorizationHelper Integration
**Issue:** None of the 5 components use ProfileAuthorizationHelper
**Impact:** No IDOR protection, no cross-guard validation
### 2. Inconsistent Authorization Checks
**Issue:** Only 2/5 components have ANY authorization (Profiles and Mailings)
**Impact:** 3 components (Posts, Categories, Tags) are completely unprotected
### 3. No Active Profile Verification
**Issue:** Components don't verify that active profile matches authenticated profile
**Impact:** Cross-guard attacks possible (similar to ExportProfileData vulnerability)
### 4. Bank Level Not Validated
**Issue:** Bank level 1 can access admin functions
**Impact:** Non-central banks have admin privileges
---
## Recommended Security Fixes
### Priority 1: CRITICAL (Posts, Categories, Tags)
**Add ProfileAuthorizationHelper to mount():**
```php
public function mount()
{
// Get active profile from session
$activeProfileType = session('activeProfileType');
$activeProfileId = session('activeProfileId');
if (!$activeProfileType || !$activeProfileId) {
abort(403, __('No active profile selected'));
}
$profile = $activeProfileType::find($activeProfileId);
if (!$profile) {
abort(403, __('Active profile not found'));
}
// Validate profile ownership using ProfileAuthorizationHelper
\App\Helpers\ProfileAuthorizationHelper::authorize($profile);
// Verify admin permissions
if (!($profile instanceof \App\Models\Admin)) {
abort(403, __('Admin access required'));
}
// Additional initialization...
}
```
### Priority 2: HIGH (Profiles, Mailings)
**Enhance existing mount() with ProfileAuthorizationHelper:**
```php
public function mount()
{
// Get active profile
$activeProfileType = session('activeProfileType');
$activeProfileId = session('activeProfileId');
if (!$activeProfileType || !$activeProfileId) {
abort(403, __('No active profile selected'));
}
$profile = $activeProfileType::find($activeProfileId);
if (!$profile) {
abort(403, __('Active profile not found'));
}
// Use ProfileAuthorizationHelper for cross-guard protection
\App\Helpers\ProfileAuthorizationHelper::authorize($profile);
// Verify admin or central bank access
if ($profile instanceof \App\Models\Admin) {
// Admin access OK
} elseif ($profile instanceof \App\Models\Bank) {
// Only central bank (level 0)
if ($profile->level !== 0) {
abort(403, __('Central bank access required'));
}
} else {
abort(403, __('Admin or central bank access required'));
}
// Continue with initialization...
}
```
### Additional Protection: Route Middleware
**Create Admin Authorization Middleware:**
```php
// app/Http/Middleware/RequireAdminProfile.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use App\Helpers\ProfileAuthorizationHelper;
class RequireAdminProfile
{
public function handle(Request $request, Closure $next)
{
$activeProfileType = session('activeProfileType');
$activeProfileId = session('activeProfileId');
if (!$activeProfileType || !$activeProfileId) {
abort(403, __('No active profile selected'));
}
$profile = $activeProfileType::find($activeProfileId);
if (!$profile) {
abort(403, __('Active profile not found'));
}
// Use ProfileAuthorizationHelper
ProfileAuthorizationHelper::authorize($profile);
// Verify admin or central bank
if ($profile instanceof \App\Models\Admin) {
return $next($request);
}
if ($profile instanceof \App\Models\Bank && $profile->level === 0) {
return $next($request);
}
abort(403, __('Admin or central bank access required'));
}
}
```
**Apply to routes:**
```php
// routes/web.php
Route::middleware(['auth', 'admin-profile'])->group(function () {
Route::get('/posts/manage', \App\Http\Livewire\Posts\Manage::class);
Route::get('/categories/manage', \App\Http\Livewire\Categories\Manage::class);
Route::get('/tags/manage', \App\Http\Livewire\Tags\Manage::class);
Route::get('/profiles/manage', \App\Http\Livewire\Profiles\Manage::class);
Route::get('/mailings/manage', \App\Http\Livewire\Mailings\Manage::class);
});
```
---
## Test Coverage Recommendations
### Posts Management Authorization Tests
```php
// tests/Feature/Security/Authorization/PostsManageAuthorizationTest.php
/** @test */
public function admin_can_access_posts_management()
{
$admin = Admin::factory()->create();
$this->actingAs($admin, 'admin');
session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);
$response = Livewire::test(\App\Http\Livewire\Posts\Manage::class);
$response->assertStatus(200);
}
/** @test */
public function user_cannot_access_posts_management()
{
$user = User::factory()->create();
$this->actingAs($user, 'web');
session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);
$response = Livewire::test(\App\Http\Livewire\Posts\Manage::class);
$response->assertStatus(403);
}
/** @test */
public function web_user_cannot_access_admin_posts_via_cross_guard_attack()
{
$user = User::factory()->create();
$admin = Admin::factory()->create();
$admin->users()->attach($user->id); // User is linked to admin
// User authenticated on 'web' guard
$this->actingAs($user, 'web');
// Malicious: manipulate session to target admin profile
session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin->id]);
$response = Livewire::test(\App\Http\Livewire\Posts\Manage::class);
$response->assertStatus(403); // Should be blocked by ProfileAuthorizationHelper
}
/** @test */
public function admin_cannot_edit_post_without_proper_authorization()
{
$admin1 = Admin::factory()->create();
$admin2 = Admin::factory()->create();
$post = Post::factory()->create();
$translation = $post->translations()->first();
$this->actingAs($admin1, 'admin');
session(['activeProfileType' => Admin::class, 'activeProfileId' => $admin1->id]);
// Attempt to manipulate session to access as different admin
session(['activeProfileId' => $admin2->id]);
$response = Livewire::test(\App\Http\Livewire\Posts\Manage::class)
->call('edit', $translation->id);
$response->assertStatus(403);
}
```
### Similar tests needed for:
- Categories Management (30+ tests)
- Tags Management (30+ tests)
- Profiles Management (40+ tests)
- Mailings Management (25+ tests)
**Total Recommended Tests:** ~150 authorization tests across 5 components
---
## Security Logging Recommendations
**Add logging to all admin operations:**
```php
// In mount() after authorization
Log::info('Admin management access', [
'component' => get_class($this),
'admin_id' => $profile->id,
'admin_type' => get_class($profile),
'authenticated_guard' => Auth::getDefaultDriver(),
'ip_address' => request()->ip(),
]);
// In sensitive operations (delete, update, etc.)
Log::warning('Admin operation performed', [
'operation' => 'delete_post',
'admin_id' => $profile->id,
'target_id' => $postId,
'ip_address' => request()->ip(),
]);
```
---
## Attack Surface Summary
| Component | Current Status | Attack Vectors | Impact Level |
|-----------|---------------|----------------|--------------|
| Posts/Manage | ❌ No protection | Session manipulation, Direct access | CRITICAL |
| Categories/Manage | ❌ No protection | Session manipulation, Direct access | CRITICAL |
| Tags/Manage | ❌ No protection | Session manipulation, Direct access | CRITICAL |
| Profiles/Manage | ⚠️ Basic check | Cross-guard attack, Bank level bypass | HIGH |
| Mailings/Manage | ⚠️ Basic check | Cross-guard attack, Bank level bypass | HIGH |
---
## Compliance Impact
### OWASP Top 10 2021
**A01:2021 Broken Access Control**
- Admin interfaces lack proper authorization
- Cross-guard attacks possible
- No IDOR protection on management endpoints
### CWE Coverage
**CWE-639: Authorization Bypass Through User-Controlled Key**
- Session manipulation allows unauthorized access
**CWE-284: Improper Access Control**
- Missing admin permission verification
- No cross-guard validation
### GDPR Compliance
⚠️ **Data Protection (Article 32)**
- Admin access to all user data not properly secured
- No audit trail for admin actions
---
## Production Deployment Blockers
**DO NOT DEPLOY TO PRODUCTION until:**
- [ ] Posts/Manage.php has ProfileAuthorizationHelper integration
- [ ] Categories/Manage.php has ProfileAuthorizationHelper integration
- [ ] Tags/Manage.php has ProfileAuthorizationHelper integration
- [ ] Profiles/Manage.php enhanced with ProfileAuthorizationHelper
- [ ] Mailings/Manage.php enhanced with ProfileAuthorizationHelper
- [ ] Admin authorization middleware created and applied
- [ ] ~150 authorization tests written and passing
- [ ] Security audit conducted on all admin endpoints
- [ ] Monitoring configured for admin access attempts
---
## Conclusion
**CRITICAL SECURITY GAPS IDENTIFIED:**
5 admin management components analyzed:
- ❌ 3 components (Posts, Categories, Tags) have **ZERO authorization protection**
- ⚠️ 2 components (Profiles, Mailings) have **insufficient protection**
- ❌ 0 components use ProfileAuthorizationHelper
- ❌ No cross-guard attack prevention
- ❌ No comprehensive authorization testing
**The admin management system is NOT PRODUCTION READY from a security perspective.**
**Immediate Actions Required:**
1. Integrate ProfileAuthorizationHelper into all 5 components
2. Add admin permission verification
3. Implement cross-guard attack prevention
4. Create comprehensive test suite (~150 tests)
5. Add security logging for all admin operations
6. Security team review before production deployment
---
**Document Version:** 1.0
**Last Updated:** 2025-12-31
**Prepared By:** Claude Code Security Audit
**Status:** ❌ CRITICAL VULNERABILITIES FOUND - NOT PRODUCTION READY