# Security Audit: withoutGlobalScopes() Usage

**Date:** 2026-04-01
**Auditor:** Laravel Engineer (Paperclip Agent)
**Task:** [ENI-8](/PAP/issues/ENI-8)

## Executive Summary

A security audit was conducted to identify and secure all usage of `withoutGlobalScopes()` in the CBT multi-tenant platform. Two methods were identified and both have been secured with explicit tenant filtering.

## Scope

This audit focused on methods that bypass the `LbbScope` tenant filtering:

1. `User::currentStudent()` - Returns Student relationship
2. `Lbb::settingsWithoutScope()` - Returns LbbSetting relationship

## Background: LbbScope

The platform uses `LbbScope` to enforce tenant isolation by automatically filtering all queries by `lbb_id` from the session:

```php
// In LbbScope::apply()
$builder->where($model->getTable() . '.lbb_id', $currentLbbId);
```

Models with `LbbScope` applied:
- Student
- LbbSetting
- Question
- Exam
- ClassModel
- Commission
- TokenTransaction
- TokenOrder

## Findings

### 1. User::currentStudent()

**Location:** `app/Models/User.php:77-80`

**Original Implementation:**
```php
public function currentStudent()
{
    return $this->hasOne(Student::class)->withoutGlobalScopes();
}
```

**Security Risk:**
- HIGH (if used without explicit filtering)
- Bypassed `LbbScope` which filters by tenant
- Could return students from ANY tenant if not properly filtered

**Current Usage Status:**
- ✅ **NOT CURRENTLY USED** anywhere in the codebase
- No active security vulnerabilities

**Mitigation Applied:**
```php
public function currentStudent()
{
    return $this->hasOne(Student::class)
        ->withoutGlobalScopes()
        ->where('students.lbb_id', session('current_lbb_id'));
}
```

**Changes Made:**
- Added explicit tenant filtering by `session('current_lbb_id')`
- Enhanced PHPDoc with security explanation and usage examples
- Method is now safe to use by default

### 2. Lbb::settingsWithoutScope()

**Location:** `app/Models/Lbb.php:157-160`

**Original Implementation:**
```php
public function settingsWithoutScope()
{
    return $this->hasOne(LbbSetting::class)->withoutGlobalScopes();
}
```

**Security Risk:**
- LOWER (but improved for defense-in-depth)
- The Lbb model itself doesn't have `LbbScope` (it IS the tenant)
- The `hasOne` relationship naturally filters via foreign key constraint
- However, explicit filtering provides defense-in-depth

**Current Usage Status:**
- ✅ **NOT CURRENTLY USED** anywhere in the codebase
- No active security vulnerabilities

**Mitigation Applied:**
```php
public function settingsWithoutScope()
{
    return $this->hasOne(LbbSetting::class)
        ->withoutGlobalScopes()
        ->where('lbb_settings.lbb_id', $this->id);
}
```

**Changes Made:**
- Added explicit tenant filtering by `$this->id` (the LBB's ID)
- Enhanced PHPDoc with security explanation
- Method is now more robust with defense-in-depth

## Safe Usage Patterns

### Pattern 1: Using currentStudent()

```php
// ✅ SAFE - Method now has built-in tenant filtering
$student = Auth::user()->currentStudent()->first();

// ✅ SAFE - Additional filtering is fine
$activeStudent = Auth::user()
    ->currentStudent()
    ->where('status', StudentStatus::ACTIVE)
    ->first();

// ❌ UNSAFE - Don't bypass withoutGlobalScopes() in controllers
$student = Auth::user()
    ->hasOne(Student::class)
    ->withoutGlobalScopes()
    ->first(); // Could return data from any tenant!
```

### Pattern 2: Using settingsWithoutScope()

```php
// ✅ SAFE - Method now has built-in tenant filtering
$lbb = Lbb::find($id);
$settings = $lbb->settingsWithoutScope()->first();

// ❌ UNSAFE - Don't query LbbSetting directly without scope
$settings = LbbSetting::withoutGlobalScopes()->first(); // Wrong tenant!
```

## Recommendations

### For Current Codebase

1. ✅ **COMPLETED**: Both methods now have explicit tenant filtering
2. ✅ **COMPLETED**: Enhanced PHPDoc with security warnings and examples
3. ✅ **COMPLETED**: Audit documented

### For Future Development

1. **Prefer Scoped Methods**: Always use methods with `LbbScope` applied by default
2. **Explicit Filtering**: When using `withoutGlobalScopes()`, ALWAYS add explicit tenant filtering
3. **Code Review**: Any new usage of `withoutGlobalScopes()` should trigger security review
4. **Testing**: Add unit tests to verify tenant isolation

### Testing Checklist

- [ ] Test `User::currentStudent()` returns only current tenant's students
- [ ] Test `Lbb::settingsWithoutScope()` returns only the specific LBB's settings
- [ ] Test with multiple tenants to ensure no cross-tenant data leakage
- [ ] Test edge cases: missing session, null values, deleted records

## Security Principles Applied

1. **Defense in Depth**: Multiple layers of tenant filtering
2. **Secure by Default**: Methods are safe to use without additional filtering
3. **Explicit over Implicit**: Tenant filtering is visible in code
4. **Documentation**: Security implications are clearly documented

## Conclusion

Both `withoutGlobalScopes()` methods have been audited and secured with explicit tenant filtering. While neither method is currently used in the codebase, they are now safe for future use. The audit also serves as documentation for security best practices in the multi-tenant CBT platform.

**Status:** ✅ COMPLETE

**Next Steps:**
- Consider adding unit tests for tenant isolation
- Monitor for any new usage of `withoutGlobalScopes()` in code reviews
- Document tenant isolation patterns in team coding standards
