CVE-2026-101041 (GCVE-0-2026-101041)
Vulnerability from cvelistv5
Published
2026-09-27 14:47
Modified
2026-09-29 15:28
Severity ?
VLAI Severity ?
EPSS score ?
Summary
The account recovery (password reset) functionality in the vulnerability-lookup web application contains a time-of-check-to-time-of-use (TOCTOU) race condition in the consumption of single-use recovery tokens. The original implementation verified the token nonce against the stored digest and then consumed (cleared) it in separate database operations. Two concurrent HTTP requests presenting the same valid recovery token could both pass the verification check before either transaction committed, allowing both to set their own password on the target account. The last transaction to commit overwrites the first, enabling an attacker who possesses a valid recovery token to replace the legitimate user's password with one of their choosing.
A secondary defect in the same endpoint (confirm_account) allowed a valid recovery link to be used to set an empty or trivially short password (e.g., three characters). The view handler performed only a manual equality comparison between the two password fields and never invoked the form's validation logic, bypassing the intended minimum-length and complexity constraints.
The affected component is the user account recovery endpoint (/user/confirm_account/<token>) and the associated token verification and consumption logic in the User model (website/models/user.py) and the view layer (website/web/views/user.py).
References
Impacted products
| Vendor | Product | Version | ||
|---|---|---|---|---|
| vulnerability-lookup | vulnerability-lookup |
Version: 0 ≤ 6.2.0 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-101041",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-09-29T15:25:10.617891Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-09-29T15:28:11.374Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"modules": [
"website/models/user.py",
"website/web/views/user.py",
"website/lib/user_utils.py"
],
"product": "vulnerability-lookup",
"programFiles": [
"website/models/user.py",
"website/web/views/user.py",
"website/lib/user_utils.py"
],
"repo": "https://github.com/vulnerability-lookup/vulnerability-lookup",
"vendor": "vulnerability-lookup",
"versions": [
{
"lessThanOrEqual": "6.2.0",
"status": "affected",
"version": "0",
"versionType": "semver"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Alexandre Dulaunoy"
},
{
"lang": "en",
"type": "remediation developer",
"value": "C\u00e9dric Bonhomme"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Claude Fable 5.1"
},
{
"lang": "en",
"type": "finder",
"value": "avrlab233"
}
],
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003eThe account recovery (password reset) functionality in the vulnerability-lookup web application contains a time-of-check-to-time-of-use (TOCTOU) race condition in the consumption of single-use recovery tokens. The original implementation verified the token nonce against the stored digest and then consumed (cleared) it in separate database operations. Two concurrent HTTP requests presenting the same valid recovery token could both pass the verification check before either transaction committed, allowing both to set their own password on the target account. The last transaction to commit overwrites the first, enabling an attacker who possesses a valid recovery token to replace the legitimate user\u0027s password with one of their choosing.\u003c/p\u003e\u003cp\u003eA secondary defect in the same endpoint (confirm_account) allowed a valid recovery link to be used to set an empty or trivially short password (e.g., three characters). The view handler performed only a manual equality comparison between the two password fields and never invoked the form\u0027s validation logic, bypassing the intended minimum-length and complexity constraints.\u003c/p\u003e\u003cp\u003eThe affected component is the user account recovery endpoint (/user/confirm_account/\u0026lt;token\u0026gt;) and the associated token verification and consumption logic in the User model (website/models/user.py) and the view layer (website/web/views/user.py).\u003c/p\u003e"
}
],
"value": "The account recovery (password reset) functionality in the vulnerability-lookup web application contains a time-of-check-to-time-of-use (TOCTOU) race condition in the consumption of single-use recovery tokens. The original implementation verified the token nonce against the stored digest and then consumed (cleared) it in separate database operations. Two concurrent HTTP requests presenting the same valid recovery token could both pass the verification check before either transaction committed, allowing both to set their own password on the target account. The last transaction to commit overwrites the first, enabling an attacker who possesses a valid recovery token to replace the legitimate user\u0027s password with one of their choosing.\n\nA secondary defect in the same endpoint (confirm_account) allowed a valid recovery link to be used to set an empty or trivially short password (e.g., three characters). The view handler performed only a manual equality comparison between the two password fields and never invoked the form\u0027s validation logic, bypassing the intended minimum-length and complexity constraints.\n\nThe affected component is the user account recovery endpoint (/user/confirm_account/\u003ctoken\u003e) and the associated token verification and consumption logic in the User model (website/models/user.py) and the view layer (website/web/views/user.py)."
}
],
"impacts": [
{
"capecId": "CAPEC-111",
"descriptions": [
{
"lang": "en",
"value": "CAPEC-111 Race Condition"
}
]
}
],
"metrics": [
{
"cvssV4_0": {
"Automatable": "NOT_DEFINED",
"Recovery": "NOT_DEFINED",
"Safety": "NOT_DEFINED",
"attackComplexity": "HIGH",
"attackRequirements": "NONE",
"attackVector": "NETWORK",
"baseScore": 6.3,
"baseSeverity": "MEDIUM",
"privilegesRequired": "NONE",
"providerUrgency": "NOT_DEFINED",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "LOW",
"subIntegrityImpact": "NONE",
"userInteraction": "NONE",
"valueDensity": "NOT_DEFINED",
"vectorString": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:L/SI:N/SA:N",
"version": "4.0",
"vulnAvailabilityImpact": "NONE",
"vulnConfidentialityImpact": "LOW",
"vulnIntegrityImpact": "NONE",
"vulnerabilityResponseEffort": "NOT_DEFINED"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-362",
"description": "CWE-362 Concurrency: Race Condition",
"lang": "en",
"type": "CWE"
}
]
},
{
"descriptions": [
{
"cweId": "CWE-20",
"description": "CWE-20 Improper Input Validation",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-09-27T14:47:57.012Z",
"orgId": "5a6e4751-2f3f-4070-9419-94fb35b644e8",
"shortName": "CIRCL"
},
"references": [
{
"name": "Security patch",
"tags": [
"patch"
],
"url": "https://github.com/vulnerability-lookup/vulnerability-lookup/commit/5462bab62d76df852619e01eb67da36c023c8c40"
},
{
"name": "Security patch",
"tags": [
"patch"
],
"url": "https://github.com/vulnerability-lookup/vulnerability-lookup/commit/ad6f22882975516adf193a1a920aaa54025c71d4"
}
],
"solutions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003eThe non-atomic check-then-consume pattern is replaced with a single conditional UPDATE statement (compare-and-set) that atomically verifies the stored SHA-256 nonce digest, updates the password hash, sets is_confirmed, and clears the token in one database operation. Only the first transaction to commit succeeds; all concurrent attempts match zero rows and are rejected with an error. The view now calls form.validate() before processing the password change, enforcing the form\u0027s length and equality validators. The dead consume_account_token() method is removed to eliminate the non-atomic consumption path entirely.\u003c/p\u003e"
}
],
"value": "The non-atomic check-then-consume pattern is replaced with a single conditional UPDATE statement (compare-and-set) that atomically verifies the stored SHA-256 nonce digest, updates the password hash, sets is_confirmed, and clears the token in one database operation. Only the first transaction to commit succeeds; all concurrent attempts match zero rows and are rejected with an error. The view now calls form.validate() before processing the password change, enforcing the form\u0027s length and equality validators. The dead consume_account_token() method is removed to eliminate the non-atomic consumption path entirely."
}
],
"title": "Vulnerability-Lookup - Race Condition in Account Recovery Token Consumption Allows Password Takeover",
"x_gcve": [
{
"extensions": {
"bcp-05-x-01": {
"ai_annotations": [
{
"ai_level": "generated",
"description": "Draft vulnerability metadata was generated from a git-format patch using an Ollama-hosted language model. Human validation is required before publication.",
"gna_source": 1,
"models": [
{
"gna_source": 1,
"identifier": "qwen3.8:27b",
"name": "qwen3.8:27b",
"source": "ollama"
}
],
"review_status": "partial",
"scope": "record",
"tags": [
"ai-computer-assisted:llm-generated",
"ai-computer-assisted:classification"
]
}
]
},
"bcp-05-x-02": {
"x_patch2vuln": {
"assumptions": [
"The product version and exact release boundary are not specified in the patch metadata; the affected version range is recorded as unspecified.",
"The CAPEC-111 mapping is the closest available pattern for a database-level TOCTOU race on a single-use token; no CAPEC specifically describes concurrent compare-and-set exploitation, so this is the best available match.",
"The CVSS AC:H reflects the race-condition aspect; the missing-validation aspect alone would be AC:L, but the patch set is treated as one vulnerability per the caller\u0027s instruction.",
"The vendor is not explicitly identified in the metadata; the GitHub repository name \u0027vulnerability-lookup\u0027 is used as the product identifier.",
"No specific authentication or deployment preconditions beyond possession of a valid recovery token are stated in the patch; the token is assumed to be delivered out-of-band (e.g., email).",
"The Co-Authored-By line for Claude Fable 5.1 is treated as a remediation developer credit per the metadata\u0027s remediation_developers list; no finder or reporter is identified in the supplied evidence."
],
"capecRationale": [
{
"capecId": "CAPEC-111",
"rationale": "The attacker exploits the window between token verification and token consumption by issuing a concurrent request with the same token. Both requests pass the check; the last to commit overwrites the first\u0027s password. This is a textbook race-condition attack on a shared resource (the single-use token). CAPEC-111 is the closest available pattern; no CAPEC specifically covers TOCTOU on database-level token consumption, so this is the best match."
}
],
"commit": "ad6f22882975516adf193a1a920aaa54025c71d4",
"confidence": "medium",
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "Alexandre Dulaunoy"
},
{
"lang": "en",
"type": "remediation developer",
"value": "C\u00e9dric Bonhomme"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Claude Fable 5.1"
}
],
"cvssRationale": "AV:N: the recovery endpoint is reachable over the network. AC:H: exploiting the race condition requires precise timing of two concurrent requests, making the attack condition high complexity. AT:N: no active user interaction or deception is required beyond possessing a valid token. PR:N: no prior authentication is needed; the recovery token itself is the credential. UI:N: no user interaction is required. VC:N: the vulnerability does not directly expose confidential data. VI:H: the integrity of the user\u0027s password (a critical credential) is directly compromised. VA:N: no availability impact. SC:N: the impact is confined to the vulnerable component. SI:H: the integrity of the user\u0027s account (password, confirmation state) is compromised, affecting the user\u0027s ability to access their own account. SA:N: no security-authority impact.",
"fixSummary": "The non-atomic check-then-consume pattern is replaced with a single conditional UPDATE statement (compare-and-set) that atomically verifies the stored SHA-256 nonce digest, updates the password hash, sets is_confirmed, and clears the token in one database operation. Only the first transaction to commit succeeds; all concurrent attempts match zero rows and are rejected with an error. The view now calls form.validate() before processing the password change, enforcing the form\u0027s length and equality validators. The dead consume_account_token() method is removed to eliminate the non-atomic consumption path entirely.",
"generatedAt": "2026-09-27T14:43:09.207406Z",
"generator": "patch2vuln.py",
"model": "qwen3.8:27b",
"modelComparison": {
"rankings": [
{
"agreementScore": 9,
"assumptionCount": 6,
"confidence": "medium",
"model": "qwen3.8:27b",
"score": 4
}
],
"selectedModel": "qwen3.8:27b",
"selectionMethod": "deterministic-consensus-v1",
"selectionNotice": "The selected result is closest to model consensus; this heuristic does not establish factual correctness and human review remains required."
},
"patchSha256": "ccb7572963e8b2435c2ee54cea019a60b1b70a5717cc3848ccd940232eae0b91",
"patchSummary": "Added reset_password_with_account_token() to the User model performing a single conditional UPDATE (WHERE id = ? AND account_token_digest = sha256(nonce)) that sets pwdhash, is_confirmed=True, and account_token_digest=None atomically. Removed the separate consume_account_token() method. Changed the confirm_account view to call form.validate() instead of only comparing password1 and password2 manually. Introduced a _account_token_digest() static helper to centralize the SHA-256 computation (previously three inline calls). Removed synchronize_session=False from the UPDATE execution options so the ORM session stays consistent. Added regression tests for concurrent token consumption (two threads, barrier-synchronized) and for rejection of passwords that fail form validation (empty, three-character, mismatched).",
"patchTruncated": false,
"patches": [
{
"commit": "5462bab62d76df852619e01eb67da36c023c8c40",
"patchSha256": "75ed8b215e2769b5d20b161ddfbde9e0b2975f836397979a94387340b0501ec1",
"source": "https://github.com/vulnerability-lookup/vulnerability-lookup/commit/5462bab62d76df852619e01eb67da36c023c8c40.patch",
"sourceUrl": "https://github.com/vulnerability-lookup/vulnerability-lookup/commit/5462bab62d76df852619e01eb67da36c023c8c40.patch",
"subject": "Fix recovery token consumption race"
},
{
"commit": "ad6f22882975516adf193a1a920aaa54025c71d4",
"patchSha256": "c1cecff5ac5f7804ff42f0583b156cefa2add775cb6f80506c917f84a26bf43d",
"source": "https://github.com/vulnerability-lookup/vulnerability-lookup/commit/ad6f22882975516adf193a1a920aaa54025c71d4.patch",
"sourceUrl": "https://github.com/vulnerability-lookup/vulnerability-lookup/commit/ad6f22882975516adf193a1a920aaa54025c71d4.patch",
"subject": "fix: [user] Validate the recovery form and harden the token"
}
],
"source": "patch set (2 sources)",
"subject": "fix: [user] Validate the recovery form and harden the token",
"weaknessRationale": [
{
"cweId": "CWE-362",
"rationale": "The primary defect is a TOCTOU race: the token nonce is verified and then consumed in separate operations, allowing two concurrent transactions to both pass verification before either commits. The fix replaces this with an atomic compare-and-set UPDATE, confirming the race condition as the root cause."
},
{
"cweId": "CWE-20",
"rationale": "The confirm_account view never called form.validate() on POST, so the form\u0027s minimum-length and equality validators were bypassed. A valid recovery link alone permitted setting an empty or three-character password. The fix adds the form.validate() call before processing."
}
]
}
}
},
"recordType": "advisory",
"vulnId": "gcve-1-2026-20252"
}
]
}
},
"cveMetadata": {
"assignerOrgId": "5a6e4751-2f3f-4070-9419-94fb35b644e8",
"assignerShortName": "CIRCL",
"cveId": "CVE-2026-101041",
"datePublished": "2026-09-27T14:47:57.012Z",
"dateReserved": "2026-09-27T14:47:50.804Z",
"dateUpdated": "2026-09-29T15:28:11.374Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"vulnerability-lookup:meta": {
"vulnrichment": {
"containers": "{\"adp\": [{\"title\": \"CISA ADP Vulnrichment\", \"metrics\": [{\"other\": {\"type\": \"ssvc\", \"content\": {\"id\": \"CVE-2026-101041\", \"role\": \"CISA Coordinator\", \"options\": [{\"Exploitation\": \"none\"}, {\"Automatable\": \"no\"}, {\"Technical Impact\": \"partial\"}], \"version\": \"2.0.3\", \"timestamp\": \"2026-09-29T15:25:10.617891Z\"}}}], \"providerMetadata\": {\"orgId\": \"134c704f-9b21-4f2e-91b3-4a467353bcc0\", \"shortName\": \"CISA-ADP\", \"dateUpdated\": \"2026-09-29T15:26:29.914Z\"}}], \"cna\": {\"title\": \"Vulnerability-Lookup - Race Condition in Account Recovery Token Consumption Allows Password Takeover\", \"x_gcve\": [{\"vulnId\": \"gcve-1-2026-20252\", \"extensions\": {\"bcp-05-x-01\": {\"ai_annotations\": [{\"tags\": [\"ai-computer-assisted:llm-generated\", \"ai-computer-assisted:classification\"], \"scope\": \"record\", \"models\": [{\"name\": \"qwen3.8:27b\", \"source\": \"ollama\", \"gna_source\": 1, \"identifier\": \"qwen3.8:27b\"}], \"ai_level\": \"generated\", \"gna_source\": 1, \"description\": \"Draft vulnerability metadata was generated from a git-format patch using an Ollama-hosted language model. Human validation is required before publication.\", \"review_status\": \"partial\"}]}, \"bcp-05-x-02\": {\"x_patch2vuln\": {\"model\": \"qwen3.8:27b\", \"commit\": \"ad6f22882975516adf193a1a920aaa54025c71d4\", \"source\": \"patch set (2 sources)\", \"credits\": [{\"lang\": \"en\", \"type\": \"remediation developer\", \"value\": \"Alexandre Dulaunoy\"}, {\"lang\": \"en\", \"type\": \"remediation developer\", \"value\": \"C\\u00e9dric Bonhomme\"}, {\"lang\": \"en\", \"type\": \"remediation developer\", \"value\": \"Claude Fable 5.1\"}], \"patches\": [{\"commit\": \"5462bab62d76df852619e01eb67da36c023c8c40\", \"source\": \"https://github.com/vulnerability-lookup/vulnerability-lookup/commit/5462bab62d76df852619e01eb67da36c023c8c40.patch\", \"subject\": \"Fix recovery token consumption race\", \"sourceUrl\": \"https://github.com/vulnerability-lookup/vulnerability-lookup/commit/5462bab62d76df852619e01eb67da36c023c8c40.patch\", \"patchSha256\": \"75ed8b215e2769b5d20b161ddfbde9e0b2975f836397979a94387340b0501ec1\"}, {\"commit\": \"ad6f22882975516adf193a1a920aaa54025c71d4\", \"source\": \"https://github.com/vulnerability-lookup/vulnerability-lookup/commit/ad6f22882975516adf193a1a920aaa54025c71d4.patch\", \"subject\": \"fix: [user] Validate the recovery form and harden the token\", \"sourceUrl\": \"https://github.com/vulnerability-lookup/vulnerability-lookup/commit/ad6f22882975516adf193a1a920aaa54025c71d4.patch\", \"patchSha256\": \"c1cecff5ac5f7804ff42f0583b156cefa2add775cb6f80506c917f84a26bf43d\"}], \"subject\": \"fix: [user] Validate the recovery form and harden the token\", \"generator\": \"patch2vuln.py\", \"confidence\": \"medium\", \"fixSummary\": \"The non-atomic check-then-consume pattern is replaced with a single conditional UPDATE statement (compare-and-set) that atomically verifies the stored SHA-256 nonce digest, updates the password hash, sets is_confirmed, and clears the token in one database operation. Only the first transaction to commit succeeds; all concurrent attempts match zero rows and are rejected with an error. The view now calls form.validate() before processing the password change, enforcing the form\u0027s length and equality validators. The dead consume_account_token() method is removed to eliminate the non-atomic consumption path entirely.\", \"assumptions\": [\"The product version and exact release boundary are not specified in the patch metadata; the affected version range is recorded as unspecified.\", \"The CAPEC-111 mapping is the closest available pattern for a database-level TOCTOU race on a single-use token; no CAPEC specifically describes concurrent compare-and-set exploitation, so this is the best available match.\", \"The CVSS AC:H reflects the race-condition aspect; the missing-validation aspect alone would be AC:L, but the patch set is treated as one vulnerability per the caller\u0027s instruction.\", \"The vendor is not explicitly identified in the metadata; the GitHub repository name \u0027vulnerability-lookup\u0027 is used as the product identifier.\", \"No specific authentication or deployment preconditions beyond possession of a valid recovery token are stated in the patch; the token is assumed to be delivered out-of-band (e.g., email).\", \"The Co-Authored-By line for Claude Fable 5.1 is treated as a remediation developer credit per the metadata\u0027s remediation_developers list; no finder or reporter is identified in the supplied evidence.\"], \"generatedAt\": \"2026-09-27T14:43:09.207406Z\", \"patchSha256\": \"ccb7572963e8b2435c2ee54cea019a60b1b70a5717cc3848ccd940232eae0b91\", \"patchSummary\": \"Added reset_password_with_account_token() to the User model performing a single conditional UPDATE (WHERE id = ? AND account_token_digest = sha256(nonce)) that sets pwdhash, is_confirmed=True, and account_token_digest=None atomically. Removed the separate consume_account_token() method. Changed the confirm_account view to call form.validate() instead of only comparing password1 and password2 manually. Introduced a _account_token_digest() static helper to centralize the SHA-256 computation (previously three inline calls). Removed synchronize_session=False from the UPDATE execution options so the ORM session stays consistent. Added regression tests for concurrent token consumption (two threads, barrier-synchronized) and for rejection of passwords that fail form validation (empty, three-character, mismatched).\", \"cvssRationale\": \"AV:N: the recovery endpoint is reachable over the network. AC:H: exploiting the race condition requires precise timing of two concurrent requests, making the attack condition high complexity. AT:N: no active user interaction or deception is required beyond possessing a valid token. PR:N: no prior authentication is needed; the recovery token itself is the credential. UI:N: no user interaction is required. VC:N: the vulnerability does not directly expose confidential data. VI:H: the integrity of the user\u0027s password (a critical credential) is directly compromised. VA:N: no availability impact. SC:N: the impact is confined to the vulnerable component. SI:H: the integrity of the user\u0027s account (password, confirmation state) is compromised, affecting the user\u0027s ability to access their own account. SA:N: no security-authority impact.\", \"capecRationale\": [{\"capecId\": \"CAPEC-111\", \"rationale\": \"The attacker exploits the window between token verification and token consumption by issuing a concurrent request with the same token. Both requests pass the check; the last to commit overwrites the first\u0027s password. This is a textbook race-condition attack on a shared resource (the single-use token). CAPEC-111 is the closest available pattern; no CAPEC specifically covers TOCTOU on database-level token consumption, so this is the best match.\"}], \"patchTruncated\": false, \"modelComparison\": {\"rankings\": [{\"model\": \"qwen3.8:27b\", \"score\": 4, \"confidence\": \"medium\", \"agreementScore\": 9, \"assumptionCount\": 6}], \"selectedModel\": \"qwen3.8:27b\", \"selectionMethod\": \"deterministic-consensus-v1\", \"selectionNotice\": \"The selected result is closest to model consensus; this heuristic does not establish factual correctness and human review remains required.\"}, \"weaknessRationale\": [{\"cweId\": \"CWE-362\", \"rationale\": \"The primary defect is a TOCTOU race: the token nonce is verified and then consumed in separate operations, allowing two concurrent transactions to both pass verification before either commits. The fix replaces this with an atomic compare-and-set UPDATE, confirming the race condition as the root cause.\"}, {\"cweId\": \"CWE-20\", \"rationale\": \"The confirm_account view never called form.validate() on POST, so the form\u0027s minimum-length and equality validators were bypassed. A valid recovery link alone permitted setting an empty or three-character password. The fix adds the form.validate() call before processing.\"}]}}}, \"recordType\": \"advisory\"}], \"credits\": [{\"lang\": \"en\", \"type\": \"remediation developer\", \"value\": \"Alexandre Dulaunoy\"}, {\"lang\": \"en\", \"type\": \"remediation developer\", \"value\": \"C\\u00e9dric Bonhomme\"}, {\"lang\": \"en\", \"type\": \"remediation developer\", \"value\": \"Claude Fable 5.1\"}, {\"lang\": \"en\", \"type\": \"finder\", \"value\": \"avrlab233\"}], \"impacts\": [{\"capecId\": \"CAPEC-111\", \"descriptions\": [{\"lang\": \"en\", \"value\": \"CAPEC-111 Race Condition\"}]}], \"metrics\": [{\"format\": \"CVSS\", \"cvssV4_0\": {\"Safety\": \"NOT_DEFINED\", \"version\": \"4.0\", \"Recovery\": \"NOT_DEFINED\", \"baseScore\": 6.3, \"Automatable\": \"NOT_DEFINED\", \"attackVector\": \"NETWORK\", \"baseSeverity\": \"MEDIUM\", \"valueDensity\": \"NOT_DEFINED\", \"vectorString\": \"CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:L/SI:N/SA:N\", \"providerUrgency\": \"NOT_DEFINED\", \"userInteraction\": \"NONE\", \"attackComplexity\": \"HIGH\", \"attackRequirements\": \"NONE\", \"privilegesRequired\": \"NONE\", \"subIntegrityImpact\": \"NONE\", \"vulnIntegrityImpact\": \"NONE\", \"subAvailabilityImpact\": \"NONE\", \"vulnAvailabilityImpact\": \"NONE\", \"subConfidentialityImpact\": \"LOW\", \"vulnConfidentialityImpact\": \"LOW\", \"vulnerabilityResponseEffort\": \"NOT_DEFINED\"}, \"scenarios\": [{\"lang\": \"en\", \"value\": \"GENERAL\"}]}], \"affected\": [{\"repo\": \"https://github.com/vulnerability-lookup/vulnerability-lookup\", \"vendor\": \"vulnerability-lookup\", \"modules\": [\"website/models/user.py\", \"website/web/views/user.py\", \"website/lib/user_utils.py\"], \"product\": \"vulnerability-lookup\", \"versions\": [{\"status\": \"affected\", \"version\": \"0\", \"versionType\": \"semver\", \"lessThanOrEqual\": \"6.2.0\"}], \"programFiles\": [\"website/models/user.py\", \"website/web/views/user.py\", \"website/lib/user_utils.py\"]}], \"solutions\": [{\"lang\": \"en\", \"value\": \"The non-atomic check-then-consume pattern is replaced with a single conditional UPDATE statement (compare-and-set) that atomically verifies the stored SHA-256 nonce digest, updates the password hash, sets is_confirmed, and clears the token in one database operation. Only the first transaction to commit succeeds; all concurrent attempts match zero rows and are rejected with an error. The view now calls form.validate() before processing the password change, enforcing the form\u0027s length and equality validators. The dead consume_account_token() method is removed to eliminate the non-atomic consumption path entirely.\", \"supportingMedia\": [{\"type\": \"text/html\", \"value\": \"\u003cp\u003eThe non-atomic check-then-consume pattern is replaced with a single conditional UPDATE statement (compare-and-set) that atomically verifies the stored SHA-256 nonce digest, updates the password hash, sets is_confirmed, and clears the token in one database operation. Only the first transaction to commit succeeds; all concurrent attempts match zero rows and are rejected with an error. The view now calls form.validate() before processing the password change, enforcing the form\u0027s length and equality validators. The dead consume_account_token() method is removed to eliminate the non-atomic consumption path entirely.\u003c/p\u003e\", \"base64\": false}]}], \"references\": [{\"url\": \"https://github.com/vulnerability-lookup/vulnerability-lookup/commit/5462bab62d76df852619e01eb67da36c023c8c40\", \"name\": \"Security patch\", \"tags\": [\"patch\"]}, {\"url\": \"https://github.com/vulnerability-lookup/vulnerability-lookup/commit/ad6f22882975516adf193a1a920aaa54025c71d4\", \"name\": \"Security patch\", \"tags\": [\"patch\"]}], \"descriptions\": [{\"lang\": \"en\", \"value\": \"The account recovery (password reset) functionality in the vulnerability-lookup web application contains a time-of-check-to-time-of-use (TOCTOU) race condition in the consumption of single-use recovery tokens. The original implementation verified the token nonce against the stored digest and then consumed (cleared) it in separate database operations. Two concurrent HTTP requests presenting the same valid recovery token could both pass the verification check before either transaction committed, allowing both to set their own password on the target account. The last transaction to commit overwrites the first, enabling an attacker who possesses a valid recovery token to replace the legitimate user\u0027s password with one of their choosing.\\n\\nA secondary defect in the same endpoint (confirm_account) allowed a valid recovery link to be used to set an empty or trivially short password (e.g., three characters). The view handler performed only a manual equality comparison between the two password fields and never invoked the form\u0027s validation logic, bypassing the intended minimum-length and complexity constraints.\\n\\nThe affected component is the user account recovery endpoint (/user/confirm_account/\u003ctoken\u003e) and the associated token verification and consumption logic in the User model (website/models/user.py) and the view layer (website/web/views/user.py).\", \"supportingMedia\": [{\"type\": \"text/html\", \"value\": \"\u003cp\u003eThe account recovery (password reset) functionality in the vulnerability-lookup web application contains a time-of-check-to-time-of-use (TOCTOU) race condition in the consumption of single-use recovery tokens. The original implementation verified the token nonce against the stored digest and then consumed (cleared) it in separate database operations. Two concurrent HTTP requests presenting the same valid recovery token could both pass the verification check before either transaction committed, allowing both to set their own password on the target account. The last transaction to commit overwrites the first, enabling an attacker who possesses a valid recovery token to replace the legitimate user\u0027s password with one of their choosing.\u003c/p\u003e\u003cp\u003eA secondary defect in the same endpoint (confirm_account) allowed a valid recovery link to be used to set an empty or trivially short password (e.g., three characters). The view handler performed only a manual equality comparison between the two password fields and never invoked the form\u0027s validation logic, bypassing the intended minimum-length and complexity constraints.\u003c/p\u003e\u003cp\u003eThe affected component is the user account recovery endpoint (/user/confirm_account/\u0026lt;token\u0026gt;) and the associated token verification and consumption logic in the User model (website/models/user.py) and the view layer (website/web/views/user.py).\u003c/p\u003e\", \"base64\": false}]}], \"problemTypes\": [{\"descriptions\": [{\"lang\": \"en\", \"type\": \"CWE\", \"cweId\": \"CWE-362\", \"description\": \"CWE-362 Concurrency: Race Condition\"}]}, {\"descriptions\": [{\"lang\": \"en\", \"type\": \"CWE\", \"cweId\": \"CWE-20\", \"description\": \"CWE-20 Improper Input Validation\"}]}], \"providerMetadata\": {\"orgId\": \"5a6e4751-2f3f-4070-9419-94fb35b644e8\", \"shortName\": \"CIRCL\", \"dateUpdated\": \"2026-09-27T14:47:57.012Z\"}}}",
"cveMetadata": "{\"cveId\": \"CVE-2026-101041\", \"state\": \"PUBLISHED\", \"dateUpdated\": \"2026-09-29T15:28:11.374Z\", \"dateReserved\": \"2026-09-27T14:47:50.804Z\", \"assignerOrgId\": \"5a6e4751-2f3f-4070-9419-94fb35b644e8\", \"datePublished\": \"2026-09-27T14:47:57.012Z\", \"assignerShortName\": \"CIRCL\"}",
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
}
}
Loading…
Loading…
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
- Confirmed: The vulnerability is confirmed from an analyst perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
- Patched: This vulnerability was successfully patched by the user reporting the sighting.
- Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
- Not confirmed: The user expresses doubt about the veracity of the vulnerability.
- Not patched: This vulnerability was not successfully patched by the user reporting the sighting.
Loading…
Loading…