{"schema":"threatline.record/2","record":{"id":"CVE-2026-58273","aliases":["GHSA-5j9r-fx4x-rpvg"],"summary":"rucio has an Authorization Bypass on REST API endpoint for signing URLs","details":"## Summary\nThe `/credentials/signurl` endpoint decides authorization from the client-supplied `X-Rucio-Account` HTTP header instead of the authenticated token's account. Any client holding **any** valid auth token (even a low-privilege account they legitimately own) can send `X-Rucio-Account: root` to pass the root-only permission check and have the Rucio server mint a presigned **read / write / delete** URL for an **arbitrary** object, signed with the RSE's stored S3 / GCS / Swift credentials.\n\n## Details\n`SignURL.get()` takes the authorization principal from a request header and\nnever uses the token-authenticated identity:\n\n```python\n# lib/rucio/web/rest/flaskapi/v1/credentials.py\naccount = request.headers.get('X-Rucio-Account', default=None)     # L165  (attacker-controlled)\n...\nresult = get_signed_url(account, rse=rse, service=service,         # L194\n                        operation=operation, url=url, lifetime=lifetime, vo=vo)\n```\n\nThe gateway then uses that header value as the `issuer` for the permission check:\n\n```python\n# lib/rucio/gateway/credential.py\nauth_result = permission.has_permission(issuer=account, vo=vo,     # L57\n                                        action='get_signed_url', kwargs=kwargs, ...)\n```\n\nand the permission function is root-only:\n\n```python\n# lib/rucio/core/permission/generic.py\ndef perm_get_signed_url(issuer, kwargs, session):\n    return _is_root(issuer)        # _is_root(x) -> x.external == 'root'\n```\n\n`InternalAccount('root', vo).external == 'root'` unconditionally, so the gate passes whenever the header is `root`. The endpoint is on `AuthenticatedBlueprint`, whose `before_request` hook validates the token and sets `request.environ['issuer']` **from the token** — but nothing ever compares `X-Rucio-Account` to it:\n\n```python\n# lib/rucio/web/rest/flaskapi/v1/common.py  (request_auth_env)\nflask.request.environ['issuer'] = auth.get('account')             # L168  (the real account; unused by SignURL)\n```\n\nThis is anomalous: every other authenticated handler derives the account from `request.environ['issuer']`; `credentials.py` is the only one that trusts the header. Additionally, `core.credential.get_signed_url` never checks that the supplied `url`'s host/bucket belongs to the target RSE, so even a legitimate `root` caller gets an arbitrary-object signing oracle. In multi-VO the VO is also read from the `X-Rucio-VO` header, allowing cross-tenant targeting.\n\n## Proof of concept\nRequest (any valid token + spoofed account):\n```\nGET /credentials/signurl?rse=<cloudRSE>&svc=s3&op=delete&url=https://victim-bucket.s3.amazonaws.com/important/dataset.root HTTP/1.1\nX-Rucio-Auth-Token: <any valid token, even a low-privilege account>\nX-Rucio-Account: root\nAccept: application/octet-stream\n```\nResponse: `200 OK` with a presigned DELETE URL the attacker replays directly against the storage backend.\n\n## Impact\nA low-privilege Rucio user can read, overwrite, and delete arbitrary objects on any cloud-backed (S3/GCS/Swift) RSE using the server's stored credentials — enabling data exfiltration, tampering, and destruction, and cross-tenant access in multi-VO deployments.\n\n## Credit\nReported by seankohjs. Found via static analysis + manual verification.","categories":["Libraries & packages"],"product":"rucio","vendor":"","ecosystem":"pip","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T19:50:05Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"ecosystem":"pip","name":"rucio"},"range":">= 1.16.1, < 35.9.0"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T19:50:05Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"ecosystem":"pip","name":"rucio"},"range":">= 36.0.0rc1, < 38.6.0"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T19:50:05Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"ecosystem":"pip","name":"rucio"},"range":">= 39.0.0rc1, < 41.0.0rc1"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T20:00:03.935383872Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"name":"rucio","ecosystem":"PyPI","purl":"pkg:pypi/rucio"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.16.1"},{"fixed":"35.9.0"}]}],"versions":["1.16.1","1.16.2","1.16.3","1.17.0","1.17.1","1.17.2","1.17.2.post1","1.17.5","1.17.6","1.17.6.post1","1.17.6.post2","1.17.7","1.17.8","1.17.8.post1","1.17.8.post2","1.18.0","1.18.1","1.18.3","1.18.4","1.18.5","1.18.5.post1","1.18.6","1.18.6.post1","1.18.7","1.18.8","1.18.8.post1","1.18.9","1.19.0.post2","1.19.1","1.19.3","1.19.4","1.19.4.post1","1.19.4.post2","1.19.5","1.19.6","1.19.7","1.19.7.post1","1.19.8","1.20.0","1.20.0rc1","1.20.1","1.20.1.post1","1.20.10","1.20.11","1.20.12","1.20.13","1.20.14","1.20.15","1.20.16","1.20.2"]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T20:00:03.935383872Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"name":"rucio","ecosystem":"PyPI","purl":"pkg:pypi/rucio"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"36.0.0rc1"},{"fixed":"38.6.0"}]}],"versions":["36.0.0","36.0.0.post1","36.0.0.post2","36.0.0rc1","36.0.0rc2","36.0.0rc3","36.0.0rc4","36.0.0rc5","36.1.0","36.2.0","36.3.0","36.4.0","36.5.0","37.0.0","37.0.0rc1","37.0.0rc2","37.0.0rc3","37.0.0rc4","37.1.0","37.1.0.post1","37.2.0","37.3.0","37.4.0","37.5.0","37.6.0","37.7.0","37.7.1","38.0.0","38.0.0rc1","38.0.0rc2","38.0.0rc3","38.1.0","38.2.0","38.3.0","38.4.0","38.5.0","38.5.1","38.5.2","38.5.3","38.5.4","38.5.5"]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T20:00:03.935383872Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"name":"rucio","ecosystem":"PyPI","purl":"pkg:pypi/rucio"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"39.0.0rc1"},{"fixed":"41.0.0rc1"}]}],"versions":["39.0.0","39.0.0rc1","39.0.0rc2","39.1.0","39.2.0","39.3.0","39.3.1","39.4.0","39.4.1","39.4.2","40.0.0","40.0.0rc1","40.1.0","40.1.1","40.1.2","40.2.0","40.3.0","40.4.0","40.4.1","40.4.2"]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T19:50:05Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"ecosystem":"pip","name":"rucio"},"version":"35.9.0"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T19:50:05Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"ecosystem":"pip","name":"rucio"},"version":"38.6.0"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T19:50:05Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"ecosystem":"pip","name":"rucio"},"version":"41.0.0rc1"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T20:00:03.935383872Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"name":"rucio","ecosystem":"PyPI","purl":"pkg:pypi/rucio"},"version":"35.9.0"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T20:00:03.935383872Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"name":"rucio","ecosystem":"PyPI","purl":"pkg:pypi/rucio"},"version":"38.6.0"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-5j9r-fx4x-rpvg","source_modified_at":"2026-10-28T20:00:03.935383872Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"name":"rucio","ecosystem":"PyPI","purl":"pkg:pypi/rucio"},"version":"41.0.0rc1"}],"cvss":8.8,"severity":"High","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-28T19:50:05Z","modified_at":"2026-10-28T20:00:03.935383872Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-5j9r-fx4x-rpvg","fetched_at":"2026-10-28T20:58:01.013507Z","source_modified_at":"2026-10-28T19:50:05Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-5j9r-fx4x-rpvg","fetched_at":"2026-10-28T20:58:01.013507Z","source_modified_at":"2026-10-28T20:00:03.935383872Z"}],"sources":["GitHub Advisory Database","OSV"],"references":[{"url":"https://github.com/rucio/rucio/security/advisories/GHSA-5j9r-fx4x-rpvg","source":"GitHub Advisory Database"},{"url":"https://github.com/rucio/rucio/commit/64c0e6a6a93ae88427ff3b7d77532ce08c8a69ec","source":"GitHub Advisory Database"},{"url":"https://github.com/rucio/rucio/commit/8bdc38994a8766658d0314d36afc104c9242c96f","source":"GitHub Advisory Database"},{"url":"https://github.com/rucio/rucio/commit/8d9ba31514e6f5dca32b8c1db4738582cb37ec3a","source":"GitHub Advisory Database"},{"url":"https://github.com/rucio/rucio/releases/tag/35.9.0","source":"GitHub Advisory Database"},{"url":"https://github.com/rucio/rucio/releases/tag/38.6.0","source":"GitHub Advisory Database"},{"url":"https://github.com/rucio/rucio/releases/tag/41.0.0rc1","source":"GitHub Advisory Database"},{"url":"https://github.com/advisories/GHSA-5j9r-fx4x-rpvg","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-28T20:00:03.935383872Z","content_hash":"ae7de02ddd1e3e99801949d97c6c675f8e7841ab2b7bf6af6aacdea03b31b057"}}
