{"id":"CVE-2026-100397","kind":"vulnerability","aliases":["CVE-2026-100397","GHSA-x585-4vv8-2mh2"],"related":[],"title":"Rucio: Unauthenticated administrator impersonation through SSH challenge tokens","description":"## Summary\n\nSSH challenge tokens are mistakenly accepted as valid credentials during the authentication token validation process.\n\nWhile an SSH challenge token is intended as a short-lived nonce for use in a subsequent SSH key exchange, the function to validate authentication tokens does not differentiate between these and actual authentication tokens. Because challenge tokens are generated based on an account name provided via headers without requiring prior authentication, an unauthenticated attacker can request a valid \"challenge\" token for any account (including administrative ones) and use it to authenticate against other API endpoints.\n\n## Proof of Concept\n\nThe vulnerability exists because SSH challenge tokens are stored in the same database table as regular authentication tokens and `validate_auth_token` in `lib/rucio/core/authentication.py` accepts these \"challenge\" tokens. An attacker can obtain a challenge token for an account such as “root” via the REST API and then present it as a valid authentication bearer token:\n\n1. Request a challenge token for an arbitrary account (e.g., \"root\"):\n   `curl -i -H \"X-Rucio-Account: root\" https://rucio/auth/ssh_challenge_token`\n2. The server returns a `200 OK` with the header `X-Rucio-SSH-Challenge-Token`.\n3. The attacker can then use this specific token within the ten-second challenge lifetime as an authentication credential in subsequent requests to the Rucio API:\n  `curl -H \"X-Rucio-Auth-Token: $CHALLENGE_TOKEN\"  https://rucio/accounts/whoami`","summary":"Rucio accepts SSH login challenge tokens as ordinary authentication tokens, so the challenge can be used as a credential. An unauthenticated attacker can request a challenge for any account, including root, and use it to act as that administrator on the Rucio API.","severity":"critical","cvss":9.8,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"rucio","fixed":["35.9.1"],"affected":">= 1.14.0.post1, < 35.9.1","ecosystem":"pypi"},{"name":"rucio","fixed":["38.6.1"],"affected":">= 36.0.0rc1, < 38.6.1","ecosystem":"pypi"},{"name":"rucio","fixed":["40.4.2"],"affected":">= 39.0.0rc1, < 40.4.2","ecosystem":"pypi"},{"name":"rucio","fixed":["41.1.1"],"affected":">= 41.0.0rc1, < 41.1.1","ecosystem":"pypi"}],"ecosystems":["pypi"],"tags":["api","cwe-287","cwe-305","package","python","rucio","self-hosted"],"not_affected_if":["api-not-exposed","no-ssh-auth","version-fixed"],"how_to_check":"- Check the installed version with `pip show rucio` and compare it to the fixed versions below.\n- Look for `validate_auth_token` in `lib/rucio/core/authentication.py` to confirm the code path is present.\n- Check whether the SSH challenge endpoint `/auth/ssh_challenge_token` is reachable from untrusted networks.","fix":"- `35.9.1` for the 35.x line\n- `38.6.1` for the 38.x line\n- `40.4.2` for the 40.x line\n- `41.1.1` for the 41.x line","status":"open","published_at":"2026-11-13T01:09:54+00:00","first_seen_at":"2026-11-13T01:10:53+00:00","triaged_at":"2026-11-13T01:12:31+00:00","updated_at":"2026-11-13T01:12:31+00:00","category":"package","confidence":0.9,"triage":{"at":"2026-11-13T01:12:31Z","model":"claude-haiku-5-5","output":{"fix":"- `35.9.1` for the 35.x line\n- `38.6.1` for the 38.x line\n- `40.4.2` for the 40.x line\n- `41.1.1` for the 41.x line","reach":"internet","title":"Rucio: unauthenticated attacker impersonates administrators using SSH challenge tokens","impact":"high","summary":"Rucio accepts SSH login challenge tokens as ordinary authentication tokens, so the challenge can be used as a credential. An unauthenticated attacker can request a challenge for any account, including root, and use it to act as that administrator on the Rucio API.","audience":"businesses","category":"package","nicknames":[],"who_cares":["rucio","python","self-hosted","api"],"confidence":0.9,"fix_status":"available","needs_auth":"no","worst_case":"Attacker gets administrator API access without any credentials","analyst_note":"","how_to_check":"- Check the installed version with `pip show rucio` and compare it to the fixed versions below.\n- Look for `validate_auth_token` in `lib/rucio/core/authentication.py` to confirm the code path is present.\n- Check whether the SSH challenge endpoint `/auth/ssh_challenge_token` is reachable from untrusted networks.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["version-fixed","no-ssh-auth","api-not-exposed"],"who_is_affected":"Deployments of the Rucio Python package that expose its REST API and have SSH-based authentication, where challenge tokens are stored in the same table as regular tokens. Any reachable API can be attacked without credentials, so instances on an internal network with no untrusted access are lower exposure but still should be patched. Teams on a fixed version listed above, or not using the REST API, can skip it.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"critical"},"cost_usd":0.000864,"input_tokens":5313,"output_tokens":666,"severity_before":"critical"},"analyst_status":null,"analyst_note":null,"search":"'-100397':11A,19A '-2026':10A,18A '-287':26B '-305':28B '1':229C '2':249C '200':254C '2mh2':16A '3':265C '4vv8':15A 'accept':36B,84C,198C 'account':63B,138C,158C,211C,237C,246C 'act':70B 'actual':127C 'administr':3A,73B,160C 'api':24B,77B,169C,218C,291C 'arbitrari':236C 'attack':56B,149C,203C,267C 'auth':194C,297C 'authent':43B,90C,119C,128C,146C,166C,190C,226C,283C 'base':135C 'bearer':227C 'challeng':7A,39B,47B,60B,80C,97C,131C,154C,179C,200C,207C,232C,263C,279C,299C 'concept':173C 'credenti':53B,87C,284C 'curl':240C,292C 'cve':9A,17A 'cwe':25B,27B 'databas':186C 'differenti':123C 'e.g':238C 'endpoint':170C 'exchang':114C 'exist':176C 'function':116C 'generat':134C 'ghsa':13A 'ghsa-x585-4vv8-2mh2':12A 'h':242C,293C 'header':142C,258C 'host':34B 'imperson':4A 'includ':64B,159C 'intend':100C 'key':113C 'lib/rucio/core/authentication.py':197C 'lifetim':280C 'live':105C 'login':38B 'mistaken':83C 'name':139C 'nonc':106C 'obtain':205C 'ok':255C 'one':161C 'ordinari':42B 'packag':29B 'present':221C 'prior':145C 'process':93C 'proof':171C 'provid':140C 'python':30B 'regular':189C 'request':58B,151C,230C,287C 'requir':144C 'rest':217C 'return':252C 'root':65B,214C,239C,247C 'rucio':1A,20A,21A,22A,23A,31B,35B,76B,245C,261C,290C,296C 'rucio/accounts/whoami':301C 'rucio/auth/ssh_challenge_token':248C 'second':278C 'self':33B 'self-host':32B 'server':251C 'short':104C 'short-liv':103C 'specif':272C 'ssh':6A,37B,79C,96C,112C,178C,262C 'store':182C 'subsequ':111C,286C 'summari':78C 'tabl':187C 'ten':277C 'ten-second':276C 'token':8A,40B,44B,81C,91C,98C,120C,129C,132C,155C,180C,191C,195C,201C,208C,228C,233C,264C,273C,298C,300C 'unauthent':2A,55B,148C 'use':50B,67B,108C,163C,270C 'valid':86C,92C,118C,153C,193C,225C 'via':141C,215C 'vulner':175C 'within':274C 'without':143C 'x':244C,260C,295C 'x-rucio-account':243C 'x-rucio-auth-token':294C 'x-rucio-ssh-challenge-token':259C 'x585':14A","nicknames":[],"mitigations":[],"who_affected":"Deployments of the Rucio Python package that expose its REST API and have SSH-based authentication, where challenge tokens are stored in the same table as regular tokens. Any reachable API can be attacked without credentials, so instances on an internal network with no untrusted access are lower exposure but still should be patched. Teams on a fixed version listed above, or not using the REST API, can skip it.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"businesses","plain_action":null,"pkeys":["rucio"],"ptokens":["rucio"],"labels":["api","critical","cwe287","cwe305","package","pypi","python","rucio","selfhosted"],"campaign_type":null,"search_a":"'-100397':11A,19A '-2026':10A,18A '2mh2':16A '4vv8':15A 'administr':3A 'challeng':7A 'cve':9A,17A 'ghsa':13A 'ghsa-x585-4vv8-2mh2':12A 'imperson':4A 'rucio':1A,20A,21A,22A,23A 'ssh':6A 'token':8A 'unauthent':2A 'x585':14A","search_b":"'-287':26B '-305':28B 'accept':36B 'account':63B 'act':70B 'administr':73B 'api':24B,77B 'attack':56B 'authent':43B 'challeng':39B,47B,60B 'credenti':53B 'cwe':25B,27B 'host':34B 'includ':64B 'login':38B 'ordinari':42B 'packag':29B 'python':30B 'request':58B 'root':65B 'rucio':31B,35B,76B 'self':33B 'self-host':32B 'ssh':37B 'token':40B,44B 'unauthent':55B 'use':50B,67B","search_c":"'1':229C '2':249C '200':254C '3':265C 'accept':84C,198C 'account':138C,158C,211C,237C,246C 'actual':127C 'administr':160C 'api':169C,218C,291C 'arbitrari':236C 'attack':149C,203C,267C 'auth':194C,297C 'authent':90C,119C,128C,146C,166C,190C,226C,283C 'base':135C 'bearer':227C 'challeng':80C,97C,131C,154C,179C,200C,207C,232C,263C,279C,299C 'concept':173C 'credenti':87C,284C 'curl':240C,292C 'databas':186C 'differenti':123C 'e.g':238C 'endpoint':170C 'exchang':114C 'exist':176C 'function':116C 'generat':134C 'h':242C,293C 'header':142C,258C 'includ':159C 'intend':100C 'key':113C 'lib/rucio/core/authentication.py':197C 'lifetim':280C 'live':105C 'mistaken':83C 'name':139C 'nonc':106C 'obtain':205C 'ok':255C 'one':161C 'present':221C 'prior':145C 'process':93C 'proof':171C 'provid':140C 'regular':189C 'request':151C,230C,287C 'requir':144C 'rest':217C 'return':252C 'root':214C,239C,247C 'rucio':245C,261C,290C,296C 'rucio/accounts/whoami':301C 'rucio/auth/ssh_challenge_token':248C 'second':278C 'server':251C 'short':104C 'short-liv':103C 'specif':272C 'ssh':79C,96C,112C,178C,262C 'store':182C 'subsequ':111C,286C 'summari':78C 'tabl':187C 'ten':277C 'ten-second':276C 'token':81C,91C,98C,120C,129C,132C,155C,180C,191C,195C,201C,208C,228C,233C,264C,273C,298C,300C 'unauthent':148C 'use':108C,163C,270C 'valid':86C,92C,118C,153C,193C,225C 'via':141C,215C 'vulner':175C 'within':274C 'without':143C 'x':244C,260C,295C 'x-rucio-account':243C 'x-rucio-auth-token':294C 'x-rucio-ssh-challenge-token':259C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-13T01:09:54+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-x585-4vv8-2mh2","url":"https://github.com/advisories/GHSA-x585-4vv8-2mh2","severity":"critical","published_at":"2026-11-13T01:09:54+00:00","modified_at":"2026-11-13T01:09:55+00:00","first_seen_at":"2026-11-13T01:10:53+00:00","fetched_at":"2026-11-13T01:26:21+00:00","note":null}],"documents":[{"id":141135,"url":"https://api.github.com/repos/rucio/rucio/security-advisories/GHSA-x585-4vv8-2mh2","title":"Maintainer's advisory: api.github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: api.github.com"},{"id":141136,"url":"https://github.com/rucio/rucio/security/advisories/GHSA-x585-4vv8-2mh2","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"},{"id":141137,"url":"https://github.com/rucio/rucio/commit/4d4a58571ba853f3a55aef16ad9eb0944fce7483","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":141138,"url":"https://github.com/rucio/rucio/commit/4df924feb539ef789b3e78cbc00712ef8cdf606e","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":141139,"url":"https://github.com/rucio/rucio/commit/8295d72a9e2d76abf9e98eb6f9a4ed5cb3bb1869","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":141140,"url":"https://github.com/rucio/rucio/commit/883d526c2f3c315cd775fb142038007053e3882b","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":141141,"url":"https://github.com/rucio/rucio/commit/b1725ee5477b683202174f0ec77ae00921bc3bd0","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":141142,"url":"https://github.com/rucio/rucio/commit/d7a3c2c2f933dce8edbcad07d8d076b9b782da35","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":141143,"url":"https://github.com/rucio/rucio/commit/e6525523e3bbe8ae34cbfc9b043ae52bda209b87","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":141144,"url":"https://github.com/rucio/rucio/commit/f5db3546d9c0de4642dc9aa52e6a6e447911d680","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":141145,"url":"https://github.com/rucio/rucio/releases/tag/35.9.1","title":"Release: github.com","kind":"release","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Release: github.com"},{"id":141146,"url":"https://github.com/rucio/rucio/releases/tag/35.9.1.post1","title":"Release: github.com","kind":"release","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Release: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}