Threat Overview
Northflank disclosed a platform security incident on October 30, 2026. Its official incident timeline directs customers to assume environment variables in workloads, secret groups, and global secrets have been decrypted. Multiple customers reported unauthorized use of AI API keys supplied to the platform. Northflank deployed network-policy changes, enabled add-on credential rotation, and made audit logs available to all customers. It has not publicly established that every secret was stolen or disclosed an entry vector, affected-customer count, or attacker identity. Potentially exposed credentials may authorize access to external AI, cloud, identity and database services.
References
Impacted Systems
Northflank managed cloud application hosting platform, workloads, secret groups, global secrets and add-on credentials. Both managed PaaS and bring-your-own-cloud deployments should assess exposure; the vendor has not published a deployment-specific impact split. There is no applicable customer software fixed version. Exposure requires secrets stored on the platform, not necessarily an Internet-facing workload. External cloud and AI API credentials may remain usable until revoked at the issuing provider. No unaffected customer population is confirmed.
Why this matters
A hosting-platform secret incident creates potential downstream cloud and identity access risk. When a possibly exposed credential authenticates to Azure, AWS or Microsoft Entra, the activity may be visible in those services’ logs if ingested into Sentinel. These queries cannot directly confirm that a credential originated in Northflank.
Exploitation Status
Confirmed vendor security incident and confirmed customer reports of unauthorized AI API-key use (October 30–31). The instruction to assume all environment variables are compromised is precautionary guidance, not proof that every secret was extracted. Entry method, actor attribution, affected-customer count and full scope remain undisclosed as of November 1.
What this hunt looks for
Prepared conditional hunts for Entra service-principal and user sign-ins, app credential changes, Azure role changes, and AWS high-risk API, secret access and IAM modifications. No customer Sentinel workspace was queried.
Required logs
- N01 — New successful service-principal source IPs: AADServicePrincipalSignInLogs
- N02 — New successful user sign-in IPs: SigninLogs
- N03 — Entra app credential and consent changes: AuditLogs
- N04 — Azure role-assignment modifications: AzureActivity
- N05 — New source IPs using high-risk AWS APIs: AWSCloudTrail
- N06 — AWS secret and parameter retrieval: AWSCloudTrail
- N07 — AWS IAM credential and trust changes: AWSCloudTrail
N01 — New successful service-principal source IPs
let baseline = AADServicePrincipalSignInLogs
| where TimeGenerated between (ago(30d)..ago(2d)) and ResultType == '0'
| summarize KnownIPs=make_set(IPAddress, 500) by ServicePrincipalId;
AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(2d) and ResultType == '0'
| join kind=leftouter baseline on ServicePrincipalId
| where isnull(KnownIPs) or not(set_has_element(KnownIPs, IPAddress))
| project TimeGenerated, ServicePrincipalName, ServicePrincipalId, IPAddress, AppId, ResultType, KnownIPs
| order by TimeGenerated desc
N02 — New successful user sign-in IPs
let baseline = SigninLogs
| where TimeGenerated between (ago(30d)..ago(2d)) and ResultType == '0'
| summarize KnownIPs=make_set(IPAddress, 500) by UserPrincipalName;
SigninLogs
| where TimeGenerated >= ago(2d) and ResultType == '0'
| join kind=leftouter baseline on UserPrincipalName
| where isnull(KnownIPs) or not(set_has_element(KnownIPs, IPAddress))
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName, ConditionalAccessStatus, ResultType
| order by TimeGenerated desc
N03 — Entra app credential and consent changes
AuditLogs
| where TimeGenerated >= ago(7d)
| where OperationName has_any ('Add service principal credentials','Add application password','Add application key','Add app role assignment','Consent to application','Add delegated permission grant','Update application')
| project TimeGenerated, OperationName, Result, InitiatedBy=tostring(InitiatedBy), TargetResources=tostring(TargetResources)
| order by TimeGenerated desc
N04 — Azure role-assignment modifications
AzureActivity
| where TimeGenerated >= ago(7d)
| where OperationNameValue has_any ('MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE','MICROSOFT.AUTHORIZATION/ROLEDEFINITIONS/WRITE')
| project TimeGenerated, Caller, CallerIpAddress, OperationNameValue, ActivityStatusValue, ResourceId, Properties=tostring(Properties)
| order by TimeGenerated desc
N05 — New source IPs using high-risk AWS APIs
let events = dynamic(['AssumeRole','GetSecretValue','GetParameter','GetParameters','CreateAccessKey','UpdateAssumeRolePolicy','PutRolePolicy','AttachRolePolicy','CreateUser']);
let baseline = AWSCloudTrail
| where TimeGenerated between (ago(30d)..ago(2d))
| where EventName in (events)
| summarize KnownIPs=make_set(SourceIpAddress, 500) by UserIdentityArn;
AWSCloudTrail
| where TimeGenerated >= ago(2d) and EventName in (events)
| join kind=leftouter baseline on UserIdentityArn
| where isnull(KnownIPs) or not(set_has_element(KnownIPs, SourceIpAddress))
| project TimeGenerated, EventName, UserIdentityArn, SourceIpAddress, AWSRegion, UserAgent, ErrorCode
| order by TimeGenerated desc
N06 — AWS secret and parameter retrieval
AWSCloudTrail
| where TimeGenerated >= ago(7d)
| where EventName in ('GetSecretValue','BatchGetSecretValue','GetParameter','GetParameters','GetParametersByPath')
| summarize Events=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), APIs=make_set(EventName,20), Regions=make_set(AWSRegion,20) by UserIdentityArn, SourceIpAddress, UserAgent
| where Events >= 3
| order by Events desc
N07 — AWS IAM credential and trust changes
AWSCloudTrail
| where TimeGenerated >= ago(7d)
| where EventName in ('CreateAccessKey','UpdateAccessKey','CreateLoginProfile','UpdateLoginProfile','UpdateAssumeRolePolicy','PutUserPolicy','PutRolePolicy','AttachUserPolicy','AttachRolePolicy','CreatePolicyVersion','SetDefaultPolicyVersion')
| project TimeGenerated, EventName, UserIdentityArn, SourceIpAddress, AWSRegion, UserAgent, ErrorCode, RequestParameters=tostring(RequestParameters)
| order by TimeGenerated desc
Detection Notes
Highest signal: N01, N04, N05 and N07 when linked to identities known to be stored in Northflank. New IPs may reflect VPNs, proxies, travel or cloud egress changes. App credential additions and Azure role changes may be authorized. AWSCloudTrail may omit data events and AI-provider usage unless explicitly collected. Northflank-native audit logs and third-party provider billing records are not confirmed as ingested in the supplied inventories. Baselines require sufficient retention. No query can prove that an observed cloud credential was obtained from Northflank.