Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐍
🐍 PyPI
Not in CISA KEV
HIGH severity

CVE-2026-58273 — rucio

HIGHFix: rucio/rucio@64c0e6a

CVE-2026-58273 is a high-severity (CVSS 8.8) vulnerability in rucio. A fix is available for rucio — see the affected versions and patch details below.

rucio has an Authorization Bypass on REST API endpoint for signing URLs

Published
Updated
Affected
3 pkgs
Patched
3 / 3
Exploits
None indexed
Exploitation data as of Oct 28, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

3 pkgs affected
🐍rucio🐍rucio🐍rucio

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

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:

# lib/rucio/web/rest/flaskapi/v1/credentials.py
account = request.headers.get('X-Rucio-Account', default=None)     # L165  (attacker-controlled)
...
result = get_signed_url(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:

# lib/rucio/gateway/credential.py
auth_result = permission.has_permission(issuer=account, vo=vo,     # L57
                                        action='get_signed_url', kwargs=kwargs, ...)

and the permission function is root-only:

# lib/rucio/core/permission/generic.py
def perm_get_signed_url(issuer, kwargs, session):
    return _is_root(issuer)        # _is_root(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 before_request hook validates the token and sets request.environ['issuer'] from the token — but nothing ever compares X-Rucio-Account to it:

# lib/rucio/web/rest/flaskapi/v1/common.py  (request_auth_env)
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.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.

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 Packages

3 total 3 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPIrucio≥ 1.16.1&&< 35.9.035.9.0pip install --upgrade 'rucio==35.9.0'
🐍PyPIrucio≥ 36.0.0rc1&&< 38.6.038.6.0pip install --upgrade 'rucio==38.6.0'
🐍PyPIrucio≥ 39.0.0rc1&&< 41.0.0rc141.0.0rc1pip install --upgrade 'rucio==41.0.0rc1'

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for rucio, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update rucio to 35.9.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-58273 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

Frequently Asked Questions

## 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 t
O3 Security · Impact-Aware SCA

Is CVE-2026-58273 in your dependencies?

Find it across PyPI, including transitive dependencies.

CVE-2026-58273: rucio — Fixed in 35.9.0