This issue has been assessed as high severity. Review affected configurations immediately.
On 9 November 2026 Wiz published research on a threat actor that used IAM credentials from an AWS account associated with Qubole to assume roles that customers had created for Qubole integrations. Wiz states it observed the activity between 14 and 26 October 2026, worked with Sentra and Mandiant, and that Sentra first spotted suspicious activity across several of its customers’ environments. This article summarizes what Wiz reported and turns its recommendations into checks you can run. Everything below about the incident is Wiz’s account; we have not independently confirmed it, and Wiz does not say how the vendor-side credentials were obtained.
What Wiz observed
Vendor integrations typically work like this: the customer creates a role whose trust policy names the vendor’s AWS account as principal, usually gated by an sts:ExternalId condition. An identity in the vendor account calls sts:AssumeRole and receives temporary credentials.
Per Wiz, the actor made AssumeRole calls from account 805246085872, which Wiz says it observes Qubole’s platform using, via two IAM users. The first calls came on 14 October from a Mullvad VPN address, later mostly from an OVH-hosted VPS. Wiz says every attributed request included an External ID and every one succeeded. In most observed environments, the actor’s requests were the only AssumeRole activity from the vendor account in October, meaning the roles were unused but still trusted.
After assuming a role the actor, according to Wiz:
- Enumerated storage and data services (for example ListBuckets, GetDatabases, ListTables), EC2, RDS, IAM roles and KMS keys, using session names beginning
quiam-. - Harvested secrets from Lambda environment variables (
GetFunctionConfiguration), Secrets Manager and SSM Parameter Store. - Used TruffleHog to test found credentials: AWS keys via
GetCallerIdentity, Entra ID service principal secrets, and Okta client credentials. - Downloaded S3 objects opportunistically, in some cases whole buckets in one session.
Wiz also reports a separate 8 to 11 October set of activity using customer-owned access keys it believes were created for Qubole integrations, which it could not link to the role-assumption campaign. It found a bootable ISO (sso_agent.iso) on the actor’s server but has not identified any deployment of it. Wiz found no ties to other publicly reported activity.
Why the External ID did not help
Wiz notes the External ID is logged in plaintext in CloudTrail and often stored by the vendor and in infrastructure-as-code. Wiz’s point is that it should not be the only control. As background (our general knowledge, not from Wiz, and not checked against AWS documentation), the External ID is designed to prevent the confused deputy problem, not to stop a compromised vendor principal that already holds the value. Our assessment: any role that trusts a vendor account root with only an External ID is exposed to whatever happens to that vendor’s credentials.
Hunt in CloudTrail
Wiz advises reviewing CloudTrail from 1 October 2026 in every account holding an integration role. Indicators (defanged): IPs 57.129.54[.]120, 45.83.220[.]211, 185.209.199[.]73, 89.37.63[.]175, 2001:41d0:70d[:]7800::; principal IDs AIDA3W7DIFLYOLTK63SFS (seen only in actor activity in the environments Wiz observed) and AIDAJYRRH5Y3A7AAJM2HW (also carries legitimate traffic, so filter on non-AWS source IPs). Mullvad exits are shared, so those IPs alone are not conclusive.
A CloudWatch Logs Insights query over a CloudTrail log group (our query; adjust field names to your log format):
fields eventTime, userIdentity.principalId, sourceIPAddress, requestParameters.roleArn, requestParameters.roleSessionName
| filter eventName = "AssumeRole" and userIdentity.accountId = "805246085872"
| filter sourceIPAddress not like /amazonaws\.com/
| sort eventTime asc
Wiz’s actual test is that the source address is not an AWS address. The not like /amazonaws\.com/ filter above is only a rough proxy (calls from AWS-hosted workloads usually log an IP, not a hostname), so expect false positives: compare against published AWS IP ranges or exclude known-good vendor IPs. Wiz also treats userIdentity.principalId = AIDA3W7DIFLYOLTK63SFS as suspicious on its own. Also search for session names matching quiam-*, and GetCallerIdentity calls with a TruffleHog user agent next to the listed IPs. If a role was assumed by the actor, Wiz says to rotate every secret, parameter and Lambda environment variable it could read, and revoke active sessions, because rotation does not end sessions already issued. CloudTrail management events record role assumption but not S3 object reads; Wiz says S3 data events or server access logs are needed to see exfiltration.
Inventory and tighten external trust
List roles that trust accounts outside your own (our command, untested; requires jq; review pagination for large accounts; it may miss roles, for example policies whose Statement is a single object rather than an array, or principal lists that mix your own account with an external one):
ME=$(aws sts get-caller-identity --query Account --output text)
aws iam list-roles --output json | jq -r --arg me "$ME" '
.Roles[] | select(.AssumeRolePolicyDocument.Statement[]?
| .Principal.AWS? // empty | tostring | test("arn:aws:iam::[0-9]{12}:") and (test($me) | not))
| .RoleName'
Wiz’s recommendations, with an example trust policy of ours (placeholders; verify in a test account before applying):
- Delete integration roles you no longer use, or remove the vendor from their trust policy.
- Replace the
:rootprincipal with the specific principal the vendor documents, where supported. - Add
aws:SourceIporaws:SourceVpcelimits to the vendor’s documented ranges. Wiz states a source IP condition alone would have blocked every role assumption it observed. - Use a distinct External ID per role and rotate it with the vendor after an event, where supported.
- Trim permissions on vendor roles, especially Lambda configuration, Secrets Manager, SSM and broad S3 read.
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::<vendor-account-id>:role/<vendor-role-name>" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "sts:ExternalId": "<unique-external-id>" },
"IpAddress": { "aws:SourceIp": ["<vendor-egress-cidr>"] }
}
}
Caveat (our assessment): an IP condition only works if the vendor publishes stable egress ranges and calls from them; a wrong range breaks the integration, so test first.
Unverified
No Qubole statement appears in the Wiz or Sentra posts as of 2026-11-11. Sentra’s post (https://sentra.io/blog/breaches/inside-the-qubole-supply-chain-attack, 9 Nov 2026) corroborates the scope and says an attacker obtained Qubole credentials and that dozens of customers were affected; those are Sentra’s claims, Sentra is Wiz’s partner on this case and refers readers to Wiz for the technical detail. We did not open the Mandiant write-up or AWS documentation. As of 2026-11-11, we did not find a CVE associated with this activity in the Wiz post; none is cited there.
References
- Wiz: Trusted by Default: Qubole Cross-Account Access Abused in the Wild (9 Nov 2026)
- Sentra: Inside the Qubole supply chain attack (9 Nov 2026) https://sentra.io/blog/breaches/inside-the-qubole-supply-chain-attack