GHSA-mwgh-92m2-wvhv AVideo: Unauthenticated CRLF/ICS Injection in Scheduler downloadICS.php Allows Calendar Event Spoofing
SummaryThe unauthenticated `plugin/Scheduler/downloadICS.php` endpoint passes attacker-controlled `title`, `description`, and `joinURL` parameters into `Scheduler::downloadICS()`, which builds an ICS calendar file via the `ICS` helper class. `ICS::escape_string()` (`objects/ICS.php:167-169`) only escapes `,` and `;` and does NOT neutralize CR/LF, so attacker CRLF bytes inside a property value break out and inject arbitrary ICS lines — including `END:VEVENT` / `BEGIN:VEVENT` pairs that add entire attacker-controlled calendar events. Because the malicious `.ics` file is served from the victim's trusted AVideo origin, this enables high-credibility calendar phishing: forged meetings with attacker-chosen `SUMMARY`, `URL`, `LOCATION`, and `DESCRIPTION` landing in the victim's calendar after import.DetailsVulnerable code path**`plugin/Scheduler/downloadICS.php`** — unauthenticated entry point:There is no session check, no CSRF token, no user-role check — only an empty-check on `title`/`date_start` and a plugin-enabled check.**`plugin/Scheduler/Scheduler.php:367-382`** passes inputs directly to the ICS builder:**`objects/ICS.php:167-169`** — incomplete escape:Per RFC 5545 §3.3.11, TEXT values must also have CR/LF either folded or encoded as `\n`. This implementation does neither. `ICS::to_string()` (line 101) joins every property with `"\r\n"`, so any raw `\r\n` sequence embedded in a value breaks out of the property line and injects new ICS directives.Verified exploit outputRunning the builder with a CRLF-laden `description` produces a file with two distinct `VEVENT` blocks (the second entirely attacker-controlled):The injected `BEGIN:VEVENT` / `END:VEVENT` pair is standards-compliant and parsed as an additional event by Outlook, Apple Calendar, Google Calendar, and Thunderbird/Lightning.PoCEnsure the Scheduler plugin is enabled on the target (default-shipped optional plugin, commonly enabled on streaming deployments).Send an unauthenticated GET request with CRLF-encoded payload in `description`:The returned file contains two `VEVENT` blocks. Import into any standards-compliant calendar client — both events appear in the victim's calendar. The injected event renders with an attacker-chosen clickable URL.Local reproduction (without needing a running server) using the same code path:Produces the two-VEVENT output shown above (verified).Impact**Same-origin calendar phishing.** The `.ics` is served from the trusted AVideo domain, bypassing URL-reputation checks and email-filter suspicion of attacker-hosted attachments.**Arbitrary event spoofing.** Attacker controls `SUMMARY`, `DTSTART`, `DTEND`, `URL`, `LOCATION`, `DESCRIPTION`, and may add further ICS properties (e.g. `ORGANIZER`, `ATTENDEE`). Many mainstream calendar clients display the `URL` field as a clickable link in the event body.**Integrity:** Low — unwanted/forged events are added to the victim's calendar after they import the file.**Auth:** None. Precondition is only that the Scheduler plugin is enabled, which is typical on deployments that use AVideo's scheduled streaming features.**Confidentiality / Availability:** No direct impact.Not a higher-severity response-splitting bug: PHP's `header()` blocks CRLF in response headers since 5.1.2, so the CRLF bytes do not escape into HTTP headers — only into the ICS body.Recommended FixStrip or RFC-5545-encode CR/LF in `ICS::escape_string()` so newline bytes cannot break out of a property line. In `objects/ICS.php:167-169`:Additionally, `plugin/Scheduler/downloadICS.php` should either require authentication or at minimum apply strict input validation (length caps, character whitelists) on `title`, `description`, and `joinURL` — and `joinURL` should continue to be validated via `isValidURL()` (already done) before emission. Consider adding a defence-in-depth strip of CR/LF on every `$_REQUEST` parameter used by `Scheduler::downloadICS()`.
CVSS v3.1 score: 4.3