{"id":26148,"date":"2026-09-21T13:06:34","date_gmt":"2026-09-21T21:06:34","guid":{"rendered":"https:\/\/www.palada.net\/index.php\/2026\/09\/21\/from-ci-cd-to-cloud-data-how-shai-hulud-persistence-leads-to-redshift-breach-3\/"},"modified":"2026-09-21T13:06:34","modified_gmt":"2026-09-21T21:06:34","slug":"from-ci-cd-to-cloud-data-how-shai-hulud-persistence-leads-to-redshift-breach-3","status":"publish","type":"post","link":"http:\/\/www.palada.net\/index.php\/2026\/09\/21\/from-ci-cd-to-cloud-data-how-shai-hulud-persistence-leads-to-redshift-breach-3\/","title":{"rendered":"From CI\/CD to Cloud Data: How Shai Hulud Persistence Leads to Redshift Breach"},"content":{"rendered":"<div class=\"Table-Content aem-GridColumn aem-GridColumn--default--12\">\n<div class=\"blog-toc\">\n<div class=\"b3-blog-list__row\">\n<div class=\"b3-blog-list__column-left table-content-wrapper automatic\">\n<ul class=\"table-of-content\">\n<li class=\"header\"><img decoding=\"async\" alt=\"\" class=\"toc-icon\" src=\"\/content\/dam\/fortinet\/images\/toc-icon.jpg\"\/>Article Contents<\/li>\n<\/ul>\n<\/div>\n<div class=\"aem-GridColumn aem-GridColumn--default--8 b3-blog-list__column-right scrolling-content automatic\">\n<div class=\"b15-blog-meta__container text-container\">\n<span>By <\/span><br \/>\n<span class=\"b15-blog-meta__author\"><br \/>\n<a href=\"\/blog\/search?author=FortiGuard+Lab\">FortiGuard Lab<\/a><br \/>\n<\/span><br \/>\n<span class=\"b15-blog-meta__\"><br \/>\n<\/span><br \/>\n<span class=\"b15-blog-meta__date\"> | June 26, 2026<\/span>\n<\/div>\n<div class=\"C875-Disclaimer\">\n<\/div>\n<div class=\"raw-import\">\n<div class=\"text-container\"><\/div>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p style=\"\tmargin-left: 80.0px;\n\"><b>Affected Platforms: <\/b>Amazon Web Services (AWS)<br \/>\n<b>Impacted Users: <\/b>Any organization<br \/>\n<b>Impact: <\/b>Stolen cloud credentials result in significant financial losses and data breaches of sensitive information.<br \/>\n<b>Severity Level: <\/b>High<\/p>\n<p>Organizations with modern CI\/CD pipelines face threats from the Shai Hulud supply chain campaign, a software worm attributed to TeamPCP that has been targeting npm and PyPI packages since late 2025. Named after the giant sandworms in <i>Dune<\/i>, Shai Hulud injects malicious packages that execute during installs or CI jobs, harvesting build credentials to move into cloud infrastructure.<\/p>\n<p>Organizations running modern CI\/CD are learning a critical lesson from the Shai Hulud supply chain campaign: a poisoned build dependency doesn&#8217;t stop at the pipeline\u2014it becomes a bridge into the production cloud.<\/p>\n<p>In May 2026, FortiCNAPP helped customers identify AWS estates affected by the worm. By mid-May, investigators found evidence of ongoing access to a Jenkins runner that matched Shai Hulud\u2019s credential-harvesting pattern. They showed that an operator had exploited the Jenkins role over the internet, escalated privileges to full cloud admin, changed database network controls, and extracted data from Amazon Redshift. They also staged activities with object storage and email.<\/p>\n<p>For leaders, the key takeaway is operational: pipeline identity equals production identity. Practitioners have a rich evidence trail if they know where to look. This blog details CloudTrail and host signals, showing how FortiCNAPP detected an intrusion with the alert \u201cPotentially Compromised Keys,\u201d helping analysts reconstruct host and cloud timelines.<\/p>\n<h2>Shai Hulud and the Cloud Threat<\/h2>\n<p>There was a sharp increase in detected instances of the Shai Hulud worm during the \u201cMini Shai Hulud\u201d wave in April\u2013May 2026. Previously observed incidents described a repeatable model:<\/p>\n<ul>\n<li>Malicious package versions execute during installations or CI jobs.<\/li>\n<li>Payloads harvest credentials from the build environment, including package registry tokens, GitHub tokens, AWS credentials, Kubernetes secrets, SSH keys, and more.<\/li>\n<li>Stolen credentials enable the autonomous republication of additional poisoned packages.<\/li>\n<li>Recent variants have abused trusted OIDC publishing in GitHub Actions, producing artifacts that appear legitimately attested even though the runner itself was attacker-influenced.<\/li>\n<\/ul>\n<p>CI\/CD runners become a vector for quickly expanding the cloud attack surface. Jenkins, GitHub Actions, and self-hosted agents routinely hold instance profiles, long-lived secrets, and network access to data tiers\u2014exactly what Shai Hulud was built to collect.<\/p>\n<h3>Timeline<\/h3>\n<\/div>\n<div class=\"cmp cmp-text\">\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" class=\"details-tbl\" width=\"100%\">\n<tbody>\n<tr>\n<td width=\"33%\"><b>Phase<\/b><\/td>\n<td width=\"33%\"><b>Approximate Date<\/b><\/td>\n<td width=\"33%\"><b>What Happened<\/b><\/td>\n<\/tr>\n<tr>\n<td>Supply chain exposure<\/td>\n<td>Early May 2026<\/td>\n<td>Environment affected by aggressive Shai Hulud activity<\/td>\n<\/tr>\n<tr>\n<td>Suspected CI persistence<\/td>\n<td>Through mid-May 2026<\/td>\n<td>Possible residual access on Jenkins \/ build infrastructure<\/td>\n<\/tr>\n<tr>\n<td>Cloud intrusion &amp; exfiltration<\/td>\n<td>Mid-May<\/td>\n<td>External use of Jenkins instance role; IAM escalation; RDS\/Redshift targeting and data exfiltration<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"\ttext-align: center;\n\"><i>Table 1. Linking Shai Hulud to the Jenkins runner<\/i><\/p>\n<p>Although there&#8217;s no definitive proof that the worm infection caused the cloud compromise, the suspected link is strongly supported.<\/p>\n<ul>\n<li><b>Temporal alignment<\/b>: Supply chain compromise in early May precedes cloud abuse by about two weeks, consistent with typical persistence-and-staging patterns.<\/li>\n<li><b>Initial cloud identity<\/b>: The first malicious CloudTrail activity used the Jenkins EC2 instance role, the same credential class that Shai Hulud families are documented to steal from CI hosts.<\/li>\n<li><b>Known worm capabilities<\/b>: TeamPCP tooling is designed to harvest cloud and CI secrets and reuse them outside the victim network; external use of instance credentials aligns with that playbook.<\/li>\n<\/ul>\n<p>Host-level forensics and analysis to trace the complete attack path, from a specific malicious package artifact to the mid-May session, remain an ongoing area of investigation.<\/p>\n<p>Figure 1, below, provides an overview of the attack and identity compromise that enable lateral movement within cloud infrastructure:<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 1: Attack overview (MITRE ATT&amp;CK)<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>The following stages describe the cloud-based activities that took place after credential theft and were identified by FortiCNAPP Alerting:<\/p>\n<ol>\n<li><b>Initial cloud access<\/b>: Instance credentials were retrieved via instance metadata on the compromised EC2. The role was then invoked from external IP addresses, not from the instance.<\/li>\n<li><b>Privilege escalation<\/b>: Attacker-created IAM user named cloudops-monitor given administrator privileges and access keys.<\/li>\n<li><b>Infrastructure manipulation<\/b>: Attacker security groups, stage EC2 instances, and modify ModifyDBCluster or ModifyCluster to attach these groups to Aurora and Redshift.<\/li>\n<li><b>Credential and data access<\/b>: Enumeration of Mass Secrets Manager; access to targeted warehouse secrets; executing Redshift Data API queries.<\/li>\n<li><b>Exfiltration<\/b>: Inline policies exfil-s3-write and exfil-s3-full; usage of AssumeRole with the session name exfil; and executing SSM SendCommand on a managed instance.<\/li>\n<li><b>Secondary staging<\/b>: Amazon SES quota and identity verification (corporate addresses redacted below).<\/li>\n<\/ol>\n<p>\u00a0<\/p>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" class=\"details-tbl\" width=\"100%\">\n<tbody>\n<tr>\n<td width=\"33%\"><b>MITRE Tactic<\/b><\/td>\n<td width=\"33%\"><b>Representative Techniques<\/b><\/td>\n<td width=\"33%\"><b>What We Observed<\/b><\/td>\n<\/tr>\n<tr>\n<td><b>Initial Access<\/b><\/td>\n<td>T1195.002 (Supply chain compromise)<\/td>\n<td>Prior Shai Hulud exposure; suspected Jenkins persistence<\/td>\n<\/tr>\n<tr>\n<td><b>Valid Accounts<\/b><\/td>\n<td>T1078.004 (Cloud accounts)<\/td>\n<td>Jenkins instance role used from external IPs<\/td>\n<\/tr>\n<tr>\n<td><b>Privilege Escalation<\/b><\/td>\n<td>T1098 (Account manipulation)<\/td>\n<td>IAM user cloudops-monitor with admin policy<\/td>\n<\/tr>\n<tr>\n<td><b>Discovery<\/b><\/td>\n<td>T1580, T1526 (Cloud infrastructure \/ IAM)<\/td>\n<td>S3, VPC, RDS, Redshift, Secrets enumeration<\/td>\n<\/tr>\n<tr>\n<td><b>Persistence<\/b><\/td>\n<td>T1578 (Modify cloud compute infra)<\/td>\n<td>Security groups, EC2, cluster SG attachment<\/td>\n<\/tr>\n<tr>\n<td><b>Credential Access<\/b><\/td>\n<td>T1552.005 (Cloud instance metadata), T1555<\/td>\n<td>IMDS curl on runner; Secrets Manager; GetClusterCredentials<\/td>\n<\/tr>\n<tr>\n<td><b>Collection<\/b><\/td>\n<td>T1530 (Data from cloud storage)<\/td>\n<td>Redshift Data API ExecuteStatement (high volume)<\/td>\n<\/tr>\n<tr>\n<td><b>Exfiltration<\/b><\/td>\n<td>T1537 (Transfer to cloud account)<\/td>\n<td>S3 policy staging; AssumeRole sessions named exfil*<\/td>\n<\/tr>\n<tr>\n<td><b>Impact<\/b><\/td>\n<td>T1496 (Resource hijacking)<\/td>\n<td>SES identity verification staging<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"\ttext-align: center;\n\"><i>Table 2. Mapping MITRE tactics to observed malware behavior<\/i><\/p>\n<h2>Bridging Host and Cloud: Port 8080 and Instance Metadata<\/h2>\n<p>The earliest high-confidence cloud signal was the use of the Jenkins instance profile outside AWS, detected by FortiCNAPP as external instance-credential abuse.<\/p>\n<p>On the Jenkins host, investigators observed access to the instance metadata service (IMDS) consistent with credential theft:<\/p>\n<p style=\"\tmargin-left: 40.0px;\n\"><i>curl -s &#8211;connect-timeout 3 hxxp:\/\/169[.]254[.]169[.]254\/latest\/meta-data\/iam\/security-credentials\/<\/i><\/p>\n<p style=\"\tmargin-left: 40.0px;\n\"><i>curl -s hxxp:\/\/169[.]254[.]169[.]254\/latest\/meta-data\/iam\/security-credentials\/jenkins<\/i><\/p>\n<p>While that explained <i>how<\/i> the role credentials could be removed from the instance, the more challenging question is <i>who managed them afterward<\/i>?<\/p>\n<p>A key piece of corroboration is network telemetry from the build environment, showing an unusual outbound connection to 89[.]22[.]231[.]63 on port 8080 during the investigation period. This same IP address was later observed as the source of the cloudops-monitor identity and of subsequent privileged escalation activities. The reuse of this IP tightly links host activity on the runner to operator infrastructure in the cloud logs, and the correlation detected by FortiCNAPP proved to be a much stronger indicator than any single detection signal.<\/p>\n<h3>Two external IPs bookend the CloudTrail story:<\/h3>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" class=\"details-tbl\" width=\"100%\">\n<tbody>\n<tr>\n<td width=\"40%\"><b>IP<\/b><\/td>\n<td width=\"60%\"><b>Role in incident<\/b><\/td>\n<\/tr>\n<tr>\n<td><b>185[.]204[.]1[.]225<\/b><\/td>\n<td>First observed abuse of Jenkins role (recon, IAM escalation)<\/td>\n<\/tr>\n<tr>\n<td><b>89[.]22[.]231[.]63<\/b><\/td>\n<td>Primary operator IP after escalation; host outbound :8080<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Stage 1: Jenkins role abuse from the internet<\/h3>\n<p>After obtaining temporary instance credentials from the compromised EC2, initial cloud authentication was detected through GetCallerIdentity and ListBuckets using the Jenkins assumed-role session. FortiCNAPP flagged the credentials being used from a non-instance IP, which should trigger immediate containment measures like disabling or restricting the instance profile and isolating the runner.<\/p>\n<p>User-agent strings in these calls form two groups (see Indicators): one linked to a Fedora\/Qubes AWS CLI build from the first IP, and another associated with an Ubuntu 26 AWS CLI build that accounts for most of the later activity. This pattern suggests either multiple operators or a change in the toolchain during the intrusion.<\/p>\n<h3>Stage 2: IAM privilege escalation via cloudops-monitor<\/h3>\n<p>While still authenticated as Jenkins, the actor:<\/p>\n<ul>\n<li>Enumerated policies on the Jenkins role.<\/li>\n<li>Created IAM user cloudops-monitor and attached AWS managed AdministratorAccess.<\/li>\n<li>Issued active access keys.<\/li>\n<\/ul>\n<p>FortiCNAPP mapped CreateUser, AttachUserPolicy, and CreateAccessKey to Privilege Escalation (TA0004) with T1078 and T1098.<\/p>\n<p>After 06:35 UTC, the bulk of activity runs as cloudops-monitor from 89[.]22[.]231[.]63.<\/p>\n<h3>Stage 3: Network persistence and datastore control-plane abuse<\/h3>\n<ol type=\"a\">\n<li><b>Security groups and staging compute<\/b><br \/>\nThe actor set up security groups with harmless-sounding descriptions like \u201cCloudOps monitoring&#8221;. They enabled SSH access from 0.0.0.0\/0 and launched EC2 instances tagged with the IAM username, trying different subnets if initial placement failed. Multiple calls to DescribeSubnets and DescribeRouteTables suggest intentional mapping of the production VPC.<\/li>\n<li><b>Aurora RDS: ModifyDBCluster<\/b><br \/>\nAgainst a production Aurora PostgreSQL cluster, CloudTrail shows:<\/p>\n<ul>\n<li>Cluster reconnaissance (DescribeDBClusters).<\/li>\n<li>ModifyDBCluster with applyImmediately: true, including an attempt to rotate the master password, followed by attempts to attach an attacker-controlled security group to the cluster.<\/li>\n<\/ul>\n<p>\nThis is control-plane aggression: the actor did not limit themselves to stealing secrets. They tried to change how the database is accessed and authenticated.<\/li>\n<li><b>Redshift: ModifyCluster and port 5439<\/b><br \/>\nFor Redshift, the actor:<\/p>\n<ul>\n<li>Enumerated clusters across non-production and production warehouse targets.<\/li>\n<li>Invoked ModifyCluster to attach the same attacker security group used for RDS.<\/li>\n<li>Called AuthorizeSecurityGroupIngress on tcp\/5439 (Redshift), allowing the staging security group to reach the warehouse security group\u2014opening a network path to the data plane.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>FortiCNAPP impossible travel and sensitive infrastructure discovery observations fired on these APIs.<\/p>\n<h3>Stage 4: Secrets manager: warehouse credentials on target<\/h3>\n<p>The actor executed hundreds of paginated ListSecrets calls, followed by GetSecretValue requests for secret names clearly linked to regional Redshift warehouses and reporting pipelines. These names included patterns like datawarehouse_redshift_* and truedata_reporting_redshift_*.<\/p>\n<p>FortiCNAPP raised \u201cSuspicious Enumeration of Cloud Secrets\u201d and Credential Access (TA0006) on cloudops-monitor.<\/p>\n<p>Secrets Manager provides the quickest access to connection strings for administrators with IAM rights but restricted network access, matching the description of this phase.<\/p>\n<h3>Stage 5: Redshift data API: collection and exfiltration<\/h3>\n<p>After network and secret access, the threat actor:<\/p>\n<ul>\n<li>Repeatedly called GetClusterCredentials against a production warehouse cluster and database.<\/li>\n<li>Issued ExecuteStatement via the Redshift Data API from the same external operator IP, with ~90 execute\/describe\/result cycles in the available log set.<\/li>\n<\/ul>\n<p>CloudTrail redacts SQL in request parameters, so individual queries are not visible during log-only review. The sustained interactive volume supports assessment of data collection and exfiltration rather than a one-off health check\u2014consistent with leadership\u2019s reporting of a confirmed warehouse breach.<\/p>\n<p>FortiCNAPP Collection (TA0009) and Impact (TA0040) observations align with this phase.<\/p>\n<h3>Stage 6: Exfiltration tradecraft\u2014explicit naming in IAM and STS<\/h3>\n<p><b>Inline S3 policies <\/b>are linked to <b>an existing analytics role<\/b>. The threat actor employed PutRolePolicy to attach specifically scoped S3 data-lake permissions to a role used for analytics workloads.<\/p>\n<p>\u00a0<\/p>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" class=\"details-tbl\" width=\"100%\">\n<tbody>\n<tr>\n<td width=\"33%\"><b>Policy name<\/b><\/td>\n<td width=\"33%\"><b>Permissions<\/b><\/td>\n<td width=\"33%\"><b>Intent (Assessed)<\/b><\/td>\n<\/tr>\n<tr>\n<td><b>exfil-s3-write<\/b><\/td>\n<td>PutObject, GetObject, ListBucket on a production data bucket<\/td>\n<td>Stage writes<\/td>\n<\/tr>\n<tr>\n<td><b>exfil-s3-full<\/b><\/td>\n<td>Above plus DeleteObject<\/td>\n<td>Full object lifecycle control<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Policy names like exfil-s3-* are rare gifts to threat hunters\u2014and warnings to teams that rely on naming conventions without content inspection.<\/p>\n<p><b>AssumeRole with session name exfil<\/b><\/p>\n<p>A separate emergency IAM user (not the attacker-created monitor account) eventually converts AssumeRole into a highly privileged break-glass role using roleSessionName: exfil after multiple denials. Following this, ListRoles and SendCommand activities were performed under sessions named exfil10 and exfil12.<\/p>\n<p><b>SSM SendCommand<\/b><\/p>\n<p>During those sessions, the actor ran SendCommand with the AWS-RunShellScript document on a managed EC2 instance (parameters are redacted in the logs). Successful invocations show in-VPC execution when external CLI access is limited, which is typical for tasks such as tooling, archiving, or transferring data to egress points.<\/p>\n<h3>Stage 7: SES\u2014staging outbound email<\/h3>\n<p>Late in the window, cloudops-monitor and associated principals executed GetSendQuota, GetIdentityVerificationAttributes, VerifyEmailIdentity, and ListIdentities. Multiple corporate mailbox addresses were submitted for verification, but they are omitted here per publication policy.<\/p>\n<p>Some SES calls originated from an in-account EC2 instance rather than from the external operator IP\u2014suggesting a shift to execution within the victim VPC while control-plane abuse continued.<\/p>\n<p>SES preparation often precedes phishing, extortion, or damage to domain reputation, so it&#8217;s important to monitor even if data exfiltration occurred elsewhere.<\/p>\n<h2>Detection with FortiCNAPP: \u201cPotentially Compromised Keys\u201d<\/h2>\n<p>FortiCNAPP consumed CloudTrail and identity context, producing 1,095 observations within the incident window. The customer-facing incident Potentially Compromised Keys provided the narrative practitioners need:<\/p>\n<p>\u00a0<\/p>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" class=\"details-tbl\" width=\"100%\">\n<tbody>\n<tr>\n<td width=\"33%\"><b>Observation Category<\/b><\/td>\n<td width=\"33%\"><b>Count (approx.)<\/b><\/td>\n<td width=\"33%\"><b>Why it Mattered<\/b><\/td>\n<\/tr>\n<tr>\n<td>Impossible travel<\/td>\n<td>202<\/td>\n<td>Operator\/API geography inconsistent with baseline<\/td>\n<\/tr>\n<tr>\n<td>MITRE Discovery<\/td>\n<td>170<\/td>\n<td>S3, RDS, Redshift, IAM recon<\/td>\n<\/tr>\n<tr>\n<td>Sensitive infrastructure discovery<\/td>\n<td>128<\/td>\n<td>Cluster and security-group mutations<\/td>\n<\/tr>\n<tr>\n<td>New API for principal<\/td>\n<td>120<\/td>\n<td>First-time APIs on compromised identities<\/td>\n<\/tr>\n<tr>\n<td>Persistence<\/td>\n<td>62<\/td>\n<td>SG and cluster modifications<\/td>\n<\/tr>\n<tr>\n<td>Privilege escalation<\/td>\n<td>52<\/td>\n<td>User creation, inline policies<\/td>\n<\/tr>\n<tr>\n<td>Outside connections<\/td>\n<td>49<\/td>\n<td>External IPs on cloud identities<\/td>\n<\/tr>\n<tr>\n<td>Credential access<\/td>\n<td>41<\/td>\n<td>Secrets Manager, GetClusterCredentials<\/td>\n<\/tr>\n<tr>\n<td>External instance credential use<\/td>\n<td>20<\/td>\n<td>Jenkins role from non-AWS IP<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"\ttext-align: center;\n\"><i>Table 3. Potentially compromised activities detected<\/i><\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 2: FortiCNAPP Alert Screenshot<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>Representative observation text seen in the export:<\/p>\n<ul>\n<li><i>Use of AWS instance credentials from an outside IP<\/i> \u2014 Jenkins role.<\/li>\n<li><i>AWS user was created<\/i> \u2014 cloudops-monitor.<\/li>\n<li><i>AWS APIs indicating Privilege Escalation (TA0004) activity were observed<\/i>.<\/li>\n<li><i>Suspicious Enumeration of Cloud Secrets Detected<\/i>.<\/li>\n<li><i>Impossible travel detected in a short time frame<\/i>.<\/li>\n<\/ul>\n<p>The platform\u2019s value lies in<b> <\/b>correlating events under a single alert title: Jenkins role \u2192 cloudops-monitor \u2192 datastore APIs \u2192 exfil session naming, eliminating the need for analysts to manually connect over 1,300 CloudTrail events spanning six hours. Notably, identifying the use of external instance credentials is crucial for linking host-based and cloud-based threats. Mapping these threats from the host to the cloud is a complex, manual process that FortiCNAPP automates effectively.<\/p>\n<h2>Recommendations for Defenders<\/h2>\n<ol>\n<li><b>Treat CI\/CD runners as tier-0 identity<\/b>: Use least-privilege instance profiles; no admin paths; no broad Secrets Manager or datastore admin access from build roles.<\/li>\n<li><b>Alert on external use of instance credentials<\/b>: This was the earliest cloud signal. Pair it with host egress rules that flag unexpected outbound connections (e.g., operator IPs on non-standard ports).<\/li>\n<li><b>Guard datastore control planes<\/b>: Alert on and enforce change control for ModifyDBCluster, ModifyCluster, and security-group ingress on 5432\/5439.<\/li>\n<li><b>Hunt explicit attacker naming<\/b>: Policy names (exfil-s3-full) and STS sessions (exfil, exfil12) should be included in high-fidelity detection rules.<\/li>\n<li><b>Run tabletops from package to warehouse<\/b>: Shai Hulud demonstrates that cloud exfiltration is a realistic outcome of a poisoned pipeline dependency.<\/li>\n<\/ol>\n<h2>Fortinet Protections<\/h2>\n<p>The malware described in this report are detected and blocked by FortiGuard Antivirus as:<\/p>\n<p style=\"\tmargin-left: 40.0px;\n\">JS\/Agent.B067!tr<br \/>\nJS\/Agent.3A86!tr<\/p>\n<p>The <a aria-label=\"FortiGuard AntiVirus service\" href=\"\/support\/support-services\/fortiguard-security-subscriptions\/antivirus\" title=\"FortiGuard AntiVirus service\">FortiGuard AntiVirus service<\/a> engine is integrated into <a aria-label=\"FortiGate\" href=\"\/products\/next-generation-firewall\" title=\"FortiGate\">FortiGate<\/a>, <a aria-label=\"FortiMail\" href=\"\/products\/email-security\" title=\"FortiMail\">FortiMail<\/a>, <a aria-label=\"FortiClient\" href=\"\/products\/endpoint-security\/forticlient\" title=\"FortiClient\">FortiClient<\/a>, and <a aria-label=\"FortiEDR\" href=\"\/products\/endpoint-security\/fortiedr\" title=\"FortiEDR\">FortiEDR<\/a>. Customers running these products with up-to-date signatures are protected against the malware components described in this report.<\/p>\n<p>The <a aria-label=\"FortiGuard Web Filtering Service\" href=\"https:\/\/www.fortiguard.com\/services\/wf\" rel=\"noopener noreferrer\" target=\"_blank\" title=\"FortiGuard Web Filtering Service\">FortiGuard Web Filtering Service<\/a> blocks the C2 server.<\/p>\n<p>Organizations seeking to strengthen foundational security awareness may also consider completing <a aria-label=\"Fortinet Certified Fundamentals\" href=\"https:\/\/training.fortinet.com\/local\/staticpage\/view.php?page=fcf_cybersecurity\" rel=\"noopener noreferrer\" target=\"_blank\" title=\"Fortinet Certified Fundamentals\">Fortinet Certified Fundamentals<\/a> (FCF) training in Cybersecurity.\u00a0 This module is designed to help end users learn to identify and protect themselves from phishing attacks.<\/p>\n<p>The <a aria-label=\"FortiGuard IP Reputation and Anti-Botnet Security Service\" href=\"\/support\/support-services\/fortiguard-security-subscriptions\/ipreputation-antibot\" title=\"FortiGuard IP Reputation and Anti-Botnet Security Service\">FortiGuard IP Reputation and Anti-Botnet Security Service<\/a> proactively blocks infrastructure associated with this campaign by correlating malicious IP intelligence collected from Fortinet\u2019s global sensor network, CERT collaborations, MITRE, trusted industry partners, and other intelligence sources.<\/p>\n<p>If you believe this or any other cybersecurity threat has impacted your organization, contact our Global <a aria-label=\"FortiGuard Incident Response Team\" href=\"https:\/\/www.fortiguard.com\/faq\/csirt-contact\" rel=\"noopener noreferrer\" target=\"_blank\" title=\"FortiGuard Incident Response Team\">FortiGuard Incident Response Team<\/a> for assistance.<\/p>\n<h2>Public IOCs<\/h2>\n<p>Validate these in your environment before blocking them. Note that user agents evolve.<\/p>\n<h3>IP addresses<\/h3>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n<tbody>\n<tr>\n<td width=\"40%\"><b>IP<\/b><\/td>\n<td width=\"60%\"><b>Context<\/b><\/td>\n<\/tr>\n<tr>\n<td>185[.]204[.]1[.]225<\/td>\n<td>Initial external abuse of Jenkins instance role<\/td>\n<\/tr>\n<tr>\n<td>89[.]22[.]231[.]63<\/td>\n<td>Primary post-escalation operator IP; <b>host outbound connection on port 8080<\/b>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>IAM account (attacker-created)<\/h3>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n<tbody>\n<tr>\n<td width=\"40%\"><b>Type<\/b><\/td>\n<td width=\"60%\"><b>Value<\/b><\/td>\n<\/tr>\n<tr>\n<td>IAM user<\/td>\n<td><b>cloudops-monitor<\/b><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>STS role session names<\/h3>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n<tbody>\n<tr>\n<td width=\"40%\"><b>Session name<\/b><\/td>\n<td width=\"60%\"><b>Context<\/b><\/td>\n<\/tr>\n<tr>\n<td>exfil<\/td>\n<td>Assumed break-glass \/ super-admin role<\/td>\n<\/tr>\n<tr>\n<td>exfil10, exfil12<\/td>\n<td>Sessions used for SSM SendCommand and follow-on activity<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>IAM inline policy names (attacker-created)<\/h3>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n<tbody>\n<tr>\n<td width=\"40%\"><b>Policy name<\/b><\/td>\n<td width=\"60%\"><b>Context<\/b><\/td>\n<\/tr>\n<tr>\n<td>exfil-s3-write<\/td>\n<td>S3 write\/list to production data bucket<\/td>\n<\/tr>\n<tr>\n<td>exfil-s3-write<\/td>\n<td>Adds s3:DeleteObject on same bucket<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>User-agent strings (representative)<\/h3>\n<p><b>Ubuntu operator toolchain (dominant, IP 89[.]22[.]231[.]63):<\/b><\/p>\n<p style=\"\tmargin-left: 40.0px;\n\"><i>aws-cli\/2.31.35 md\/awscrt#1.0.0.dev0 ua\/2.1 os\/linux#7.0.0-15-generic md\/arch#x86_64 lang\/python#3.14.4 md\/pyimpl#CPython &#8230; md\/distrib#ubuntu.26<\/i><\/p>\n<p style=\"\tmargin-left: 40.0px;\n\"><i>Boto3<\/i>\/1.40.72 md\/Botocore#1.40.72 &#8230; os\/linux#7.0.0-15-generic &#8230; lang\/python#3.14.4<\/p>\n<p><b>Fedora\/Qubes toolchain (early Jenkins-role abuse, IP 185[.]204[.]1[.]225):<\/b><\/p>\n<p style=\"\tmargin-left: 40.0px;\n\"><i>aws-cli\/2.34.29 md\/awscrt#0.31.2 ua\/2.1 os\/linux#6.18.15-1.qubes.fc41.x86_64 md\/arch#x86_64 lang\/python#3.14.3 md\/pyimpl#CPython &#8230; md\/distrib#fedora.42<\/i><\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Affected Platforms: Amazon Web Services (AWS)<br \/>\nImpacted Users: Any organization<br \/>\nImpact: Stolen cloud credentials result in significant financial losses and data breaches of sensitive information.<br \/>\nSeverity Level: High<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[10424,10378,32774],"tags":[],"class_list":["post-26148","post","type-post","status-publish","format-standard","hentry","category-fortinet","category-security","category-threats"],"_links":{"self":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/26148","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/comments?post=26148"}],"version-history":[{"count":0,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/26148\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/media?parent=26148"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/categories?post=26148"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/tags?post=26148"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}