CVE-2026-53636 Overview
CVE-2026-53636 is an authentication weakness in the Open edX Platform's Learning Tools Interoperability (LTI) Provider implementation. The validate_timestamp_and_nonce function in lms/djangoapps/lti_provider/signature_validator.py does not validate OAuth nonces or timestamps. An attacker who captures a valid LTI launch request can replay it an unlimited number of times without detection. The issue is classified under CWE-294: Authentication Bypass by Capture-replay and was patched in commit 3a5ac85.
Critical Impact
Captured LTI 1.1 OAuth-signed launch requests can be replayed indefinitely, allowing unauthorized re-entry into LMS content and potential impersonation of an already-launched LTI session.
Affected Products
- Open edX Platform (LMS component) — versions prior to commit 3a5ac85
- lms/djangoapps/lti_provider Django app implementing 1EdTech LTI 1.1 provider
- Multi-node LMS deployments lacking a shared Django cache backend
Discovery Timeline
- 2026-09-02 - CVE-2026-53636 published to NVD
- 2026-09-02 - Last updated in NVD database
Technical Details for CVE-2026-53636
Vulnerability Analysis
Open edX includes a Django app that implements the server (provider) side of the 1EdTech LTI 1.1 specification. LTI 1.1 relies on OAuth 1.0-signed requests, where each request carries an oauth_nonce and oauth_timestamp. Correct OAuth 1.0 signature validation requires the provider to reject any request whose nonce has already been observed within the timestamp validity window.
In vulnerable versions, validate_timestamp_and_nonce returns success without inspecting either value. An attacker who intercepts one signed launch request, such as through a compromised proxy, browser history, or referrer logs, can resubmit that exact request to the LMS. The provider treats each replay as a fresh, valid launch. Successful exploitation requires user interaction and a captured, still-valid launch payload, which limits attack complexity but does not prevent abuse.
Root Cause
The root cause is a missing anti-replay control [CWE-294]. OAuth 1.0's replay protection is not intrinsic to signature verification; it must be implemented by tracking previously seen nonces per consumer within a bounded time window. The vulnerable validate_timestamp_and_nonce implementation was effectively a no-op, so any replayed request that still carried a valid HMAC signature was accepted.
Attack Vector
The attack is network-based and requires user interaction (the original victim must have performed a legitimate LTI launch). An attacker obtains a captured LTI launch URL or form POST, then submits it to the Open edX LMS endpoint. Because the signature is still valid and nonces are not tracked, the LMS establishes an LTI session tied to the original user's identity claims from the tool consumer.
// Patch context: shared cache is now required for nonce tracking
+The LTI provider protects against OAuth replay attacks by storing each
+``oauth_nonce`` in Django's cache after it is first seen and rejecting any
+subsequent request that presents the same nonce within the validity window
+(±5 minutes around the ``oauth_timestamp``).
+
+**This protection only works correctly when all LMS nodes share the same cache
+backend.** If you run more than one LMS process or server, you must configure
+Django's ``default`` cache to use a shared backend such as Redis or Memcached.
// Source: https://github.com/openedx/openedx-platform/commit/3a5ac856c79557c5c74d8b3e6578f289d7cceecd
Detection Methods for CVE-2026-53636
Indicators of Compromise
- Duplicate oauth_nonce values observed in LMS access logs for LTI launch endpoints within short intervals.
- Multiple LTI launches from different source IP addresses using identical oauth_signature values.
- LTI launch requests with oauth_timestamp values noticeably older than the current server time.
Detection Strategies
- Enable verbose logging on the lms/djangoapps/lti_provider endpoints and index request parameters, including oauth_nonce, oauth_timestamp, and oauth_consumer_key.
- Build a query that groups LTI launches by (oauth_consumer_key, oauth_nonce) and alerts when the count exceeds one.
- Correlate LTI launch events with subsequent user activity for anomalous geolocation or user-agent changes tied to the same LTI-provisioned account.
Monitoring Recommendations
- Monitor the Django default cache for the presence and hit rate of stored LTI nonces after applying the patch, to confirm the protection is active.
- Alert on LMS nodes where CACHES['default'] resolves to LocMemCache or any per-process backend in a multi-node deployment.
- Track error rates for LTI signature validation to spot attacker probing after the fix is deployed.
How to Mitigate CVE-2026-53636
Immediate Actions Required
- Update Open edX Platform to a build that includes commit 3a5ac85 or the corresponding backport commits 0a92cf2 and 50af17b.
- Configure a shared Django cache backend (Redis or Memcached) as the default cache on every LMS node before enabling the LTI provider.
- Rotate LTI shared secrets for any consumer whose signed launch requests may have been logged or exposed.
- Review LMS access logs for duplicated oauth_nonce values that predate the patch deployment.
Patch Information
The vulnerability is fixed in Open edX commit 3a5ac85, with related changes in commits 0a92cf2 and 50af17b. The fix implements nonce tracking in Django's cache with a ±5 minute timestamp validity window. Coordinated details are published in GitHub Security Advisory GHSA-6gm5-c49g-p3h9.
Workarounds
- If patching is not immediately possible, disable the LTI Provider Django app until the update can be deployed.
- Restrict access to LTI launch endpoints via network controls, allowing traffic only from trusted tool consumers.
- Reduce OAuth timestamp tolerance at an upstream reverse proxy to shrink the replay window for captured requests.
# Verify a shared cache is configured before enabling the LTI provider
# Example Django settings snippet for a Redis-backed default cache
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://redis.internal:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
},
},
}
# Confirm LocMemCache is not in use across LMS nodes
grep -R "LocMemCache" /edx/app/edxapp/ || echo "OK: no per-process cache backend detected"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.
