CVE-2026-58273: High severity pip/rucio vulnerability
Summary The /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.
Details SignURL.get() takes the authorization principal from a request header and never uses the token-authenticated identity:
python lib/rucio/web/rest/flaskapi/v1/credentials.py account = request.headers.get('X-Rucio-Account', default=None) # L165 (attacker-controlled) ... result = getsignedurl(account, rse=rse, service=service, # L194 operation=operation, url=url, lifetime=lifetime, vo=vo)
The gateway then uses that header value as the issuer for the permission check:
python lib/rucio/gateway/credential.py authresult = permission.haspermission(issuer=account, vo=vo, # L57 action='getsignedurl', kwargs=kwargs, ...)
and the permission function is root-only:
python lib/rucio/core/permission/generic.py def permgetsignedurl(issuer, kwargs, session): return isroot(issuer) # isroot(x) -> x.external == 'root'
InternalAccount('root', vo).external == 'root' unconditionally, so the gate passes whenever the header is root. The endpoint is on AuthenticatedBlueprint, whose beforerequest hook validates the token and sets request.environ['issuer'] from the token — but nothing ever compares X-Rucio-Account to it:
python lib/rucio/web/rest/flaskapi/v1/common.py (requestauthenv) flask.request.environ['issuer'] = auth.get('account') # L168 (the real account; unused by SignURL)
This 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.getsignedurl 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.
Proof of concept Request (any valid token + spoofed account): GET /credentials/signurl?rse=<cloudRSE>&svc=s3&op=delete&url=https://victim-bucket.s3.amazonaws.com/important/dataset.root HTTP/1.1 X-Rucio-Auth-Token: <any valid token, even a low-privilege account> X-Rucio-Account: root Accept: application/octet-stream Response: 200 OK with a presigned DELETE URL the attacker replays directly against the storage backend.
Impact A 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.
Credit Reported by seankohjs. Found via static analysis + manual verification.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/rucioto a version that resolves this vulnerability.Fixed in 41.0.0rc1 - Upgrade
Upgrade
pip/rucioto a version that resolves this vulnerability.Fixed in 38.6.0 - Upgrade
Upgrade
pip/rucioto a version that resolves this vulnerability.Fixed in 35.9.0
Event History
Frequently Asked Questions
Who can exploit this issue?
Any client with a valid Rucio authentication token, including a legitimately obtained low-privilege account token, can exploit it. The attacker can supply X-Rucio-Account: root to satisfy the root-only authorization check.
What access can an attacker obtain through exploitation?
An attacker can cause the server to mint presigned read, write, or delete URLs for arbitrary objects. Those URLs are signed using the RSE's stored S3, GCS, or Swift credentials.
What condition indicates that a deployment is affected?
A deployment is affected if its /credentials/signurl endpoint uses the client-provided X-Rucio-Account header as the authorization principal rather than the account authenticated by the token. In that condition, testing with a valid non-root token and X-Rucio-Account: root would reach the root-only signed-URL permission check as root.