A CISA contractor left privileged AWS GovCloud keys in a public GitHub repository — production credentials to government cloud infrastructure, sitting in the open until this weekend. That sets the tone for a Monday that also brings an unpatched Exchange zero-day under active exploitation, a Microsoft IR report proving that stolen credentials alone are sufficient for full cloud-environment breach, and three separate developer supply-chain compromises that landed within days of each other.

In the News

CISA Contractor Leaked AWS GovCloud Keys on Public GitHub

A contractor working for the Cybersecurity and Infrastructure Security Agency published credentials to multiple privileged AWS GovCloud accounts and internal CISA deployment systems in a public GitHub repository. The keys were live and accessible until remediation over the weekend of May 17-18. This was not a sandbox or demo environment — the exposed secrets provided access to production government cloud infrastructure.

The exposure was reported by Krebs on Security, which confirmed the credentials were functional and mapped to internal CISA tooling. The contractor’s repository had been public for an unspecified period before the keys were discovered and revoked.

This is a textbook failure of two controls: secret scanning and least-privilege IAM. Automated secret detection — running on every push, across every repository, including personal accounts used for work — would have caught the keys before they became public. Least-privilege IAM policies would have limited the blast radius even after exposure, ensuring that a single set of credentials could not reach across multiple privileged accounts.

What defenders should do: Implement pre-commit secret scanning hooks and organization-level GitHub secret scanning alerts. Audit whether contractor and third-party developer accounts are covered by the same secret detection policies as internal repositories. Rotate any credentials that have ever been committed to a repository, even if the commit was subsequently deleted — Git history preserves deleted content.

Microsoft Exchange Zero-Day (CVE-2026-42897) Under Active Attack — No Patch Available

An actively exploited cross-site scripting vulnerability in Microsoft Exchange Server (CVE-2026-42897) enables attackers to compromise Outlook Web Access mailboxes. Dark Reading reported that Microsoft has confirmed the vulnerability but has not released a patch. The flaw is being exploited in the wild against organizations running on-premises Exchange with OWA exposed to the internet.

XSS in OWA is not a theoretical risk — it gives attackers the ability to execute arbitrary script in the context of an authenticated user’s mailbox session. That means reading email, exfiltrating attachments, creating inbox rules to forward messages to external addresses, and potentially pivoting to other services that share the same session context. The attack surface is every on-prem Exchange server with OWA reachable from the internet.

With no patch available, defenders are limited to compensating controls. Restrict OWA access to managed devices via conditional access policies. Deploy email security gateway inspection that can sanitize or block exploit payloads before they reach Exchange. Monitor for the creation of suspicious inbox rules (especially forwarding rules targeting external domains) as a detection signal for post-exploitation activity. Organizations that can disable OWA entirely without business impact should do so until Microsoft ships a fix.

What defenders should do: Restrict OWA to managed devices and compliant browsers via conditional access. Deploy email security gateway controls. Monitor Exchange message tracking logs and inbox rule creation for signs of exploitation. Disable OWA if operationally feasible until a patch is available.

Storm-2949 Turned Stolen Credentials Into Cloud-Wide Breach — No Malware Required

Microsoft’s incident response team published a detailed report on Storm-2949, a threat actor that executed a full cloud-environment breach using only stolen credentials and native platform tooling. The operation spanned M365, Azure Storage, Azure SQL, and Azure virtual machines. No malware was deployed at any stage.

The kill chain began with compromised credentials and self-service password reset (SSPR) abuse from an unmanaged device. The attacker then escalated access through consent grant manipulation — registering an OAuth application and granting it broad permissions — and used native Azure APIs to enumerate and exfiltrate data across services. The lateral movement was entirely within the identity and data planes; no network-level exploitation occurred.

This is the operational reality of cloud-native breach: the perimeter is identity, and the attack surface is every API endpoint that trusts a valid token. Detection depends on monitoring SSPR events from unmanaged devices (MITRE ATT&CK T1078.004 — Valid Accounts: Cloud Accounts), alerting on new OAuth consent grants with broad scopes (T1550.001 — Use Alternate Authentication Material: Application Access Token), and tracking anomalous cross-service data access patterns that indicate exfiltration.

What defenders should do: Enforce phishing-resistant MFA for all accounts, especially those with SSPR capability. Restrict SSPR to managed and compliant devices via conditional access. Implement consent grant policies that require admin approval for applications requesting sensitive scopes. Deploy UEBA or XDR correlation that can detect bulk data access across Azure Storage, SQL, and M365 within a single identity session.

Developer Supply Chain Under Siege — npm, VS Code, and GitHub Actions All Compromised

Three distinct supply-chain attacks converged this week, all targeting the developer toolchain:

Shai-Hulud worm clones on npm: Less than a week after the TeamPCP offensive framework was open-sourced, threat actors deployed infostealer variants as npm packages targeting developer environments. BleepingComputer reported that the clones are already live and actively harvesting credentials from developer workstations.

Nx Console VS Code extension hijacked: The Nx Console extension, with over 2.2 million installations, was compromised in version 18.95.0 to deliver a credential-stealing payload. The Hacker News confirmed the malicious version was distributed through the official VS Code Marketplace. Any developer who auto-updated to v18.95.0 is potentially exposed.

GitHub Actions tag tampering: Attackers rewrote all Git tags in the popular actions-cool/issues-helper GitHub Actions workflow to point at a malicious commit that exfiltrates CI/CD secrets — tokens, API keys, deployment credentials — from every pipeline that references the action. The Hacker News reported the tag rewrite affected all version references.

The pattern is unmistakable: initial access is shifting from the network perimeter to the developer workstation and build pipeline. These three incidents, occurring within the same week, demonstrate that supply-chain attacks are not isolated events — they are a systematic targeting of the software development lifecycle (MITRE ATT&CK T1195.002 — Supply Chain Compromise: Compromise Software Supply Chain).

What defenders should do: Pin GitHub Actions dependencies by commit SHA, not by tag — tags can be rewritten. Audit VS Code extensions installed across developer workstations and remove or downgrade Nx Console if v18.95.0 was installed. Run software composition analysis on every build. Restrict CI/CD pipeline credentials using short-lived tokens with minimal scope. Monitor npm package installation events on developer endpoints for known-malicious package names.

Today’s Deep Dive — Identity-Only Cloud Breach: What Storm-2949 Means for Cloud Defense

The Storm-2949 report is worth lingering on because it represents the breach model that most cloud security architectures are still not built to detect: no malware, no exploit, no vulnerability — just a valid identity token and the native capabilities of the platform.

The Kill Chain, Step by Step

Initial access (T1078.004): The attacker obtained valid credentials — the report does not specify the initial credential theft mechanism, but the entry point was a standard user account. From an unmanaged device, they triggered a self-service password reset to take ownership of the account and set a new password.

Persistence and escalation (T1550.001): With a fresh password and no phishing-resistant MFA in the path, the attacker registered a new OAuth application and consented to broad permissions — including Mail.Read, Files.ReadWrite.All, and Azure Storage access. This consent grant gave them a persistent, token-based access path that survived subsequent password changes on the original account.

Lateral movement and exfiltration (T1530): Using the OAuth application’s tokens, Storm-2949 enumerated Azure Storage blobs, queried Azure SQL databases, and accessed M365 mailboxes and SharePoint document libraries. Data exfiltration was conducted through legitimate API calls — the same APIs that backup agents, reporting tools, and legitimate applications use every day.

Why Traditional Controls Failed

Network-based detection was irrelevant — all traffic was to legitimate Microsoft endpoints over TLS. Endpoint detection and response was irrelevant — no malware was executed, no suspicious process was spawned, no persistence mechanism was installed on any endpoint. The entire operation lived in the identity and data planes.

The controls that would have stopped this are identity-centric:

  1. Phishing-resistant MFA (FIDO2 or certificate-based) on all accounts eliminates credential replay and makes SSPR abuse from unmanaged devices impossible.
  2. Conditional access policies restricting SSPR to managed, compliant devices prevent attackers from resetting passwords from infrastructure they control.
  3. Consent grant policies requiring admin approval for any application requesting sensitive scopes (Mail.Read, Files.ReadWrite.All) block the escalation step entirely.
  4. Cross-service anomaly detection — a UEBA or XDR platform that correlates a new consent grant, followed by bulk data access across multiple Azure services, within a single identity session — provides the detection signal. The individual API calls are benign. The pattern is not.

MITRE ATT&CK Mapping

Technique IDNameStorm-2949 Usage
T1078.004Valid Accounts: Cloud AccountsInitial access via stolen credentials
T1098.003Account Manipulation: Additional Cloud RolesSSPR abuse to take account ownership
T1550.001Use Alternate Authentication Material: Application Access TokenOAuth consent grant for persistent access
T1530Data from Cloud StorageExfiltration from Azure Storage and SQL
T1114.002Email Collection: Remote Email CollectionM365 mailbox access via Graph API

Detection Spotlight

Detect suspicious OAuth consent grants in Azure AD / Entra ID — the pivotal escalation step in the Storm-2949 kill chain. This Splunk SPL query identifies new OAuth application consent events with high-risk permission scopes, correlated against unmanaged device signals.

index=azure sourcetype="azure:audit"
  operationName="Consent to application"
  | spath output=targetApp path=targetResources{}.displayName
  | spath output=consentedScopes path=targetResources{}.modifiedProperties{}.newValue
  | where match(consentedScopes, "(?i)(Mail\.Read|Files\.ReadWrite|User\.ReadWrite|Directory\.Read)")
  | eval risk_score=case(
      match(consentedScopes, "Mail\.Read") AND match(consentedScopes, "Files\.ReadWrite"), "CRITICAL",
      match(consentedScopes, "Mail\.Read") OR match(consentedScopes, "Files\.ReadWrite"), "HIGH",
      1==1, "MEDIUM")
  | table _time, initiatedBy.user.userPrincipalName, targetApp, consentedScopes, risk_score
  | sort - _time

This query surfaces consent grants that request the specific scope combinations Storm-2949 used. False positive rate is low in environments where OAuth application deployment follows a formal approval process — any consent grant that bypasses that process is worth investigating. In environments where self-service consent is broadly permitted, expect higher volume and prioritize by the risk_score field.

For KQL (Microsoft Sentinel):

AuditLogs
| where OperationName == "Consent to application"
| mv-expand TargetResources
| extend ConsentedScopes = tostring(TargetResources.modifiedProperties[0].newValue)
| where ConsentedScopes has_any ("Mail.Read", "Files.ReadWrite", "User.ReadWrite.All")
| project TimeGenerated, InitiatedBy.user.userPrincipalName, TargetResources.displayName, ConsentedScopes
| sort by TimeGenerated desc

References


Subscribe to the it-learn Brief

Get the daily cybersecurity brief in your inbox every weekday morning — news, SE angles, and detection queries.