An attacker broke into AWS accounts belonging to multiple Qubole customers between October 14 and October 26, stealing stored secrets and data.
The entry point was a credential for the AWS account that Qubole's platform uses to reach those customers. How the attacker obtained it has not been disclosed.
The uncomfortable part is what happened next. Most of the roles the attacker assumed were unused, according to Wiz's researchers. The customers had stopped using Qubole. They just never removed the trust relationship, and that was enough.
How the Trust Model Works
Qubole, a data lake platform owned by Idera, operates inside its customers' AWS accounts. To get in, a customer creates an IAM role with a trust policy that allows Qubole's AWS account to assume it.
Every AssumeRole request must include a matching code from Qubole called an External ID. That code is supposed to add a layer of verification.
It does not work the way many people assume.
AWS's own external ID guidance states that the code is not treated as a secret. Anyone with access to the role can view it. The researchers confirmed that every AssumeRole request tied to the attacker carried an External ID and was accepted.
So the control existed. It just did not control anything.
What the Attacker Did Inside
In the accounts the researchers examined, the attacker went straight for stored credentials.
|
Target |
Action |
|
Lambda |
Read environment variables |
|
Secrets Manager |
Pulled stored secrets |
|
SSM Parameter Store |
Read parameter values |
|
TruffleHog |
Validated harvested credentials |
|
S3 |
Copied data from any accessible bucket |
The harvested credentials included victims' own AWS access keys, Entra ID client secrets, and Okta client credentials.
The S3 access is worth noting separately. The attacker did not search for specific data. It retrieved from any bucket the role could reach, and sometimes downloaded an entire bucket in a single session.
The Second Activity Window
From October 8 to October 11, a separate attacker used customers' own AWS access keys, which the researchers believe had been set up for Qubole. That attacker compromised a few victims' cloud environments.
This activity has not been linked to the AssumeRole abuse, and it operated on a different timeline.
How to Check Your Accounts
Wiz's hunting guidance is specific. Review CloudTrail logs from October 1 onward in every AWS account that holds a Qubole role.
|
Indicator |
What to Look For |
|
Account |
AssumeRole requests where userIdentity.accountId is 805246085872 and sourceIPAddress is not an AWS address |
|
IAM principal |
AIDA3W7DIFLYOLTK63SFS — only the attacker used this in examined accounts |
|
IAM principal |
AIDAJYRRH5Y3A7AAJM2HW, when the source address is outside AWS |
|
IP |
57.129.54[.]120, 2001:41d0:70d[:]7800:: (OVH-hosted) |
|
IP |
45.83.220[.]211, 185.209.199[.]73, 89.37.63[.]175 (Mullvad VPN, shared with other users) |
|
Session name |
Role sessions starting with quiam-, such as quiam-enum |
|
User agent |
TruffleHog on GetCallerIdentity calls from the IPs above |
Qubole's legitimate traffic came only from AWS addresses. That is the cleanest signal.
For every suspicious session, review what it did afterward, especially in Secrets Manager, SSM Parameter Store, Lambda, and S3.
The Logging Gap That Hid the Damage
CloudTrail management events log each AssumeRole request and bucket listing. They do not log which S3 objects were read.
That requires S3 data events or S3 server access logs. Several victims did not have those enabled, so responders could not determine which objects the attacker had read.
That is the practical consequence of a logging gap. It is not that the attack goes undetected. It is that you cannot scope the breach after the fact.
How to Close the Route
Wiz's remediation list is direct and worth working through in order.
- If the attacker assumed one of your Qubole roles: rotate all secrets, parameters, and Lambda environment variables that role could reach. Then revoke the role's active sessions. Rotating a credential does not end sessions that were already issued. Those are separate actions.
- Remove unused Qubole roles. Or remove Qubole's account from the trust policy. If you are not using Qubole, you do not need to trust it.
- Swap the root principal for a specific IAM principal. Where Qubole supports it, replace the account-wide :root principal in the trust policy with the specific IAM principal Qubole actually uses.
- Add a source restriction. An aws:SourceIp or aws:SourceVpce condition limits AssumeRole requests to the vendor's documented network ranges. The researchers' assessment is blunt. A source IP condition alone would have blocked every role assumption they observed.
- Stop treating the External ID as a secret. It is logged in plain text in CloudTrail, and vendors and infrastructure-as-code files often store it. It is not your only control, and after an incident like this it should be rotated to Qubole and varied per role where possible.
- Review what each vendor role can reach. Qubole's setup guide includes a sample S3 policy that lets the role read every bucket in the account. Vendor roles commonly get broad Lambda, Secrets Manager, SSM, and S3 read permissions for convenience. Those permissions are the blast radius.
- Alert on geography. Set alerts for AssumeRole requests from a vendor account that arrive through a VPN or a hosting provider the vendor has not used before.
- Close the logging gap. Log every account and region with an organization trail. Enable S3 data events or server access logs for buckets that store sensitive data.
Why This Is a Structural Problem
The Qubole breach is not a story about one vendor making a mistake. It is a story about how cross-account trust relationships work in practice.
A customer creates a role. The vendor assumes it. The relationship stays in place for years, long after the customer stops using the product. Nobody audits it because nobody remembers it exists.
Then the vendor's credential leaks, and every forgotten trust relationship becomes an entry point.
The researchers noted that the targeting does not match what state-backed groups usually go after, and they have not linked this to any other publicly reported activity. That matters less than it might seem. A financially motivated actor with stolen vendor credentials and a list of trusting roles does not need state sponsorship to cause damage.
FAQ
What happened in the Qubole breach?
An attacker obtained credentials for the AWS account Qubole's platform uses, then assumed IAM roles in customer accounts and stole stored secrets and data between October 14 and October 26.
How did the External ID not prevent this?
Because the External ID is not a secret. AWS's own guidance says anyone with access to the role can view it, and it is logged in plain text in CloudTrail. The attacker had valid External IDs.
Was my company affected?
If you have a Qubole role in your AWS account, even an unused one, check CloudTrail from October 1 onward for AssumeRole requests from account 805246085872 with a source address outside AWS.
What did the attacker steal?
Lambda environment variables, Secrets Manager secrets, SSM Parameter Store values, and data from any S3 bucket the roles could reach. It validated credentials with TruffleHog.
What are the key indicators?
Account 805246085872, IAM principals AIDA3W7DIFLYOLTK63SFS and AIDAJYRRH5Y3A7AAJM2HW, OVH IPs 57.129.54[.]120 and 2001:41d0:70d[:]7800::, Mullvad IPs 45.83.220[.]211, 185.209.199[.]73, 89.37.63[.]175, and session names starting with quiam-.
Why can't I tell which S3 objects were read?
Because CloudTrail management events log the AssumeRole and the bucket listing, not the object reads. You need S3 data events or server access logs, and several victims did not have them enabled.
Does rotating credentials fix it?
Not alone. Rotating a credential does not terminate sessions that were already issued. You also need to revoke the role's active sessions.
What single control would have blocked this?
A source IP condition. The researchers stated that an aws:SourceIp condition alone would have blocked every role assumption they observed.
Should I trust the External ID?
Not as a security control. Treat it as a coordination mechanism, not a secret. Rotate it after an incident and use different values per role where possible.