Detection Engineering Brief - Monday, November 9, 2026

Threat intelligence translated into detection engineering action.

By DevSecOpsDad

Detection Engineering Summary

This brief produced 3 detection candidates.

2 production candidates, 0 hunting-only, 1 require environment mapping, and 0 rejected.

3 detections include KQL. 3 include ATT&CK mappings. 3 include triage guidance.

Search metadata extracted for this run includes: GitHub, OAuth applications, cloud identity tenants, ARTEX, Storm-3358, CVE-2026-123158, Cowrie, SSH, Linux, Unix, T1528, T1078.004, T1078, T1595, T1110.

No explicit IOCs were preserved for this run.

Deployment blockers or scheduling gates were identified for: SSH Exploitation Scanning Spike Targeting Linux Hosts - CVE-2026-123158.

Detection candidates were derived from recent cybersecurity reporting, operational threat research, RSS intelligence feeds, and related detection engineering sources.



Detection 1: OAuth App Permission Grant Followed by Anomalous Service Principal Sign-In

Detection Opportunity

Compromised OAuth application secrets used to perform authenticated actions within a tenant, following credential exposure on GitHub.

Intelligence Context

Search Metadata

  • CVEs: Not specified
  • Threat actors: Not specified
  • ATT&CK tags: T1528, T1078.004, T1078
  • Products: OAuth applications, GitHub
  • Platforms: cloud identity tenants
  • Malware: Not specified
  • Tools: ARTEX
  • Search tags: GitHub, OAuth applications, cloud identity tenants, ARTEX, T1528, T1078.004, T1078

Relevant IOCs

No explicit IOCs were preserved for this detection.

Metadata

  • Readiness: production candidate
  • Platform: Microsoft Sentinel
  • Analytic type: correlation
  • Severity recommendation: high
  • MITRE ATT&CK: Initial Access: T1528 Steal Application Access Token (medium); Valid Accounts: T1078 Valid Accounts/ T1078.004 Cloud Accounts (high)

Deployment Gates

  • No gate-level deployment blockers identified.

Required telemetry:

  • AuditLogs, SigninLogs

KQL

let GrantWindow = 2h;
let BaselineDays = 30d;
let RecentGrants = AuditLogs
| where TimeGenerated > ago(7d)
| where OperationName in ("Add app role assignment to service principal", "Consent to application", "Add OAuth2PermissionGrant")
| where Result == "success"
| extend AppId = tostring(TargetResources[0].id)
| where isnotempty(AppId)
| project GrantTime = TimeGenerated, AppId, GrantOperationName = OperationName, InitiatedByUPN = tostring(InitiatedBy.user.userPrincipalName);
let KnownSPIPs = SigninLogs
| where TimeGenerated between (ago(BaselineDays) .. ago(7d))
| where ServicePrincipalId != ""
| where ResultType == 0
| summarize HistoricalSigninCount = count(), KnownIPs = make_set(IPAddress, 500) by AppId;
let RecentSPSignins = SigninLogs
| where TimeGenerated > ago(7d)
| where ServicePrincipalId != ""
| where ResultType == 0
| where isnotempty(IPAddress)
| project SigninTime = TimeGenerated, AppId, ServicePrincipalName, IPAddress;
RecentGrants
| join kind=inner RecentSPSignins on AppId
| where SigninTime between (GrantTime .. (GrantTime + GrantWindow))
| join kind=leftouter KnownSPIPs on AppId
| where not(IPAddress in (KnownIPs))
| project
    GrantTime,
    SigninTime,
    AppId,
    ServicePrincipalName,
    InitiatedByUPN,
    IPAddress,
    GrantOperationName,
    HistoricalSigninCount = coalesce(HistoricalSigninCount, 0)
| order by GrantTime desc

False Positives / Tuning / Risks / Caveats

Expected false positives:

  • Legitimate new service principal deployments where an admin grants permissions and the application immediately authenticates from a new cloud IP (e.g., new Azure region, new CI/CD runner).
  • Applications that rotate IPs frequently (e.g., serverless functions, container workloads) may appear as new-IP sign-ins after any grant event.
  • First-time onboarding of third-party SaaS integrations that receive a consent grant and then authenticate immediately.

Tuning notes:

  • Widen GrantWindow to 24h or 48h if threat intelligence indicates delayed credential use after exposure.
  • Add an exclusion for known automation service principal names (e.g., those matching naming conventions for CI/CD pipelines) to reduce noise from legitimate deployments.
  • Consider adding a filter on IPAddress to exclude known corporate egress IPs or cloud provider IP ranges if those are expected sources for service principal authentication.
  • If TargetResources[0].id consistently returns object IDs rather than client IDs in your environment, extract the appId property from TargetResources using tostring(TargetResources[0].modifiedProperties) parsing.

Risks / caveats:

  • AuditLogs and SigninLogs require Entra ID Diagnostic Settings to be configured and streaming to the Sentinel workspace; if not configured, both tables will be empty.
  • ServicePrincipalId in SigninLogs is only populated for service principal sign-ins, not user sign-ins; environments without service principal activity will produce no results from the SPSignins subquery.
  • TargetResources[0].id in AuditLogs contains the object ID of the target resource, not necessarily the OAuth AppId (client ID); in some audit events this field holds the service principal object ID rather than the application client ID, which may cause join mismatches with SigninLogs.AppId.
  • The 30-day baseline window requires at least 30 days of SigninLogs retention; workspaces with shorter retention will have an incomplete known-IP baseline, increasing false positives.

Triage Runbook

First 15 minutes:

  • Confirm the grant event is legitimate by identifying the initiating user, app owner, and change ticket or deployment record.
  • Validate the service principal sign-in occurred after the grant and from an IP not previously associated with the app.
  • Check whether the app has high-privilege permissions such as Mail.Read, Files.Read.All, Directory.Read.All, or offline_access.
  • Review recent Entra ID audit activity for follow-on actions by the same app or service principal, especially consent changes, role assignments, or mailbox/file access.

Evidence to collect:

  • GrantTime, SigninTime, AppId, ServicePrincipalName, InitiatedByUPN, IPAddress, GrantOperationName, HistoricalSigninCount.
  • AuditLogs entries for the app/service principal in the 24 hours before and after the alert.
  • SigninLogs for the same AppId to identify additional source IPs, user agents, and repeated sign-ins.
  • Any related Entra ID role assignments, consent grants, or application credential changes tied to the same AppId.

Pivot points:

  • AuditLogs filtered on the AppId and GrantOperationName to enumerate all recent permission and credential changes.
  • SigninLogs filtered on AppId or ServicePrincipalId to find other sign-ins from the same app and any additional anomalous IPs.
  • If available, review Microsoft 365 or workload audit logs for actions performed by the service principal after sign-in.
  • Use Entra ID application and service principal views to confirm owners, permissions, and credential age.

Benign explanations:

  • A legitimate new deployment or CI/CD runner may grant permissions and immediately authenticate from a new cloud IP.
  • A third-party SaaS integration may be onboarded for the first time and appear as a new-IP sign-in after consent.
  • An application may rotate infrastructure or move regions, causing a first-seen IP after a valid grant.

Escalation criteria:

  • The app has privileged permissions and the initiating user cannot justify the grant.
  • The sign-in IP is external or unexpected and there is no approved deployment or onboarding record.
  • Follow-on activity shows data access, role changes, or additional consent/credential modifications.
  • Multiple service principals or apps show similar grant-then-new-IP behavior in a short period.

Containment actions:

  • Disable or revoke the suspicious OAuth application credentials if abuse is likely.
  • Revoke the app consent or remove high-risk permissions pending validation.
  • Invalidate active sessions/tokens for the service principal and investigate the initiating admin account.
  • Block the source IP only if it is clearly malicious and not shared with legitimate cloud services.

Closure criteria:

  • The grant is confirmed as approved and the sign-in matches expected deployment behavior.
  • No additional suspicious actions are found in AuditLogs or workload logs.
  • The app owner confirms the IP, timing, and permissions are expected.
  • Any risky permissions or credentials were reviewed and either validated or remediated.



Detection 2: Service Principal Sign-In Spike from New IP After OAuth App Activity - Storm-3358 Pattern

Detection Opportunity

Storm-3358 abuses exposed OAuth application secrets to authenticate into cloud identity tenants, targeting financial-sector organizations.

Intelligence Context

Search Metadata

  • CVEs: Not specified
  • Threat actors: Storm-3358
  • ATT&CK tags: T1528, T1078.004, T1078
  • Products: OAuth applications, GitHub
  • Platforms: cloud identity tenants
  • Malware: Not specified
  • Tools: ARTEX
  • Search tags: Storm-3358, GitHub, OAuth applications, cloud identity tenants, ARTEX, T1528, T1078.004, T1078

Relevant IOCs

No explicit IOCs were preserved for this detection.

Metadata

  • Readiness: production candidate
  • Platform: Microsoft Sentinel
  • Analytic type: scheduled_rule
  • Severity recommendation: high
  • MITRE ATT&CK: Initial Access: T1528 Steal Application Access Token (medium); Valid Accounts: T1078 Valid Accounts/ T1078.004 Cloud Accounts (high)

Deployment Gates

  • No gate-level deployment blockers identified.

Required telemetry:

  • AuditLogs, SigninLogs

KQL

let LookbackDays = 30d;
let CredEventWindow = 48h;
let KnownSPIPs = SigninLogs
| where TimeGenerated between (ago(LookbackDays) .. ago(1d))
| where ServicePrincipalId != ""
| where ResultType == 0
| summarize KnownIPs = make_set(IPAddress, 500) by AppId;
let RecentCredEvents = AuditLogs
| where TimeGenerated > ago(CredEventWindow)
| where OperationName in ("Add service principal credentials", "Consent to application", "Add app role assignment to service principal")
| where Result == "success"
| extend AppId = tostring(TargetResources[0].id)
| where isnotempty(AppId)
| project AppId, CredEventTime = TimeGenerated, CredOperationName = OperationName;
SigninLogs
| where TimeGenerated > ago(1d)
| where ServicePrincipalId != ""
| where ResultType == 0
| where isnotempty(IPAddress)
| join kind=inner KnownSPIPs on AppId
| where not(IPAddress in (KnownIPs))
| join kind=inner RecentCredEvents on AppId
| where TimeGenerated > CredEventTime
| where TimeGenerated <= (CredEventTime + CredEventWindow)
| extend MinutesSinceCredEvent = datetime_diff('minute', TimeGenerated, CredEventTime)
| project
    TimeGenerated,
    AppId,
    ServicePrincipalName,
    IPAddress,
    CredEventTime,
    CredOperationName,
    MinutesSinceCredEvent
| order by TimeGenerated desc

False Positives / Tuning / Risks / Caveats

Expected false positives:

  • Legitimate new service principal deployments where credentials are added and the application authenticates from a new cloud or CI/CD IP.
  • Applications migrated to new infrastructure (new IP range) shortly after a credential rotation or consent re-grant.
  • Third-party SaaS integrations that receive consent and authenticate immediately from a new IP.

Tuning notes:

  • Extend LookbackDays to 60 or 90 days for environments with stable, long-lived service principals to build a more complete IP baseline.
  • Narrow CredEventWindow to 24h or 12h to focus on immediate post-exposure authentication, which is more characteristic of automated secret harvesting tools like ARTEX.
  • Add exclusions for known automation service principal names or known cloud provider IP ranges (e.g., Azure datacenter IPs) if those generate noise.
  • Consider adding a country-based anomaly filter if the environment has a known geographic footprint for service principal authentication.

Risks / caveats:

  • AuditLogs and SigninLogs require Entra ID Diagnostic Settings to be configured and streaming to the Sentinel workspace; if not configured, both tables will be empty.
  • TargetResources[0].id in AuditLogs may contain a service principal object ID rather than the OAuth application client ID depending on the audit operation type, which can cause join mismatches with SigninLogs.AppId.
  • 30-day baseline lookback requires the workspace to retain SigninLogs for at least 30 days; default Sentinel retention is 90 days but may be reduced in cost-optimized configurations.
  • The 30-day baseline requires at least 30 days of SigninLogs history; shorter retention periods will produce an incomplete known-IP baseline and increase false positives.

Triage Runbook

First 15 minutes:

  • Verify the credential or consent event occurred within the 48-hour window before the sign-in spike.
  • Check whether the source IP is new for the AppId and whether the sign-in volume is unusual for that service principal.
  • Identify the initiating user or admin account and confirm whether the OAuth activity was expected.
  • Look for immediate post-authentication actions such as permission changes, mailbox access, file access, or additional sign-ins from the same app.

Evidence to collect:

  • TimeGenerated, AppId, ServicePrincipalName, IPAddress, CredEventTime, CredOperationName, MinutesSinceCredEvent.
  • Known IP history for the AppId and any other recent IPs used by the same service principal.
  • AuditLogs entries for the credential/consent event and any subsequent app role assignments or permission grants.
  • Any workload audit logs showing actions performed by the app after the sign-in.

Pivot points:

  • SigninLogs for the AppId to identify all sign-ins, user agents, and source IPs in the last 7 days.
  • AuditLogs for the AppId to enumerate credential additions, consent grants, and role assignments.
  • If the tenant has M365 audit data, pivot to Exchange, SharePoint, or Graph activity tied to the service principal.
  • Use Entra ID service principal and application records to confirm ownership, credential age, and expected infrastructure.

Benign explanations:

  • A legitimate app deployment or credential rotation may produce a new-IP sign-in shortly after a valid OAuth change.
  • A SaaS integration or automation platform may authenticate from a new cloud region or runner IP.
  • A newly migrated workload may not yet have a complete IP baseline, making the first valid sign-in appear anomalous.

Escalation criteria:

  • The app has sensitive permissions and the sign-in is from an unrecognized external IP.
  • The initiating admin or app owner cannot explain the credential or consent event.
  • There is evidence of data access, privilege changes, or repeated sign-ins from additional new IPs.
  • The app is associated with a financial-sector tenant or other high-value environment and the behavior matches the Storm-3358 pattern.

Containment actions:

  • Revoke the suspicious service principal credentials or disable the app if abuse is confirmed or strongly suspected.
  • Revoke recent consent grants and remove unnecessary permissions.
  • Reset or disable the initiating admin account if it appears compromised.
  • Coordinate with identity administrators to block further sign-ins from the app until ownership and legitimacy are verified.

Closure criteria:

  • The credential or consent event is validated as legitimate and the new IP is explained by approved infrastructure.
  • No post-authentication malicious activity is found in audit or workload logs.
  • The app owner confirms the sign-in pattern and source IPs are expected.
  • Any suspicious credentials or permissions have been removed or remediated.



Detection 3: SSH Exploitation Scanning Spike Targeting Linux Hosts - CVE-2026-123158

Detection Opportunity

Increased exploitation attempts against exposed SSH services consistent with active scanning for CVE-2026-123158.

Intelligence Context

  • SANS ISC: Scans for Sshole Vulnerability (CVE-2026-123158), (Sun, Nov 8th) — https://isc.sans.edu/diary/rss/33498
    • Context: SANS ISC observed an increase in exploitation attempts targeting SSH services for CVE-2026-123158, with repeated authentication attempts from external IPs against Linux hosts.

Search Metadata

  • CVEs: CVE-2026-123158
  • Threat actors: Not specified
  • ATT&CK tags: T1595, T1110
  • Products: Cowrie, SSH
  • Platforms: Linux, Unix
  • Malware: Not specified
  • Tools: Cowrie
  • Search tags: CVE-2026-123158, Cowrie, SSH, Linux, Unix, T1595, T1110

Relevant IOCs

No explicit IOCs were preserved for this detection.

Metadata

  • Readiness: requires environment mapping
  • Platform: Both
  • Analytic type: scheduled_rule
  • Severity recommendation: medium
  • MITRE ATT&CK: Reconnaissance: T1595 Active Scanning (high); Initial Access: T1110 Brute Force (medium)

Deployment Gates

  • Environment-specific telemetry or field mapping must be resolved for Both: Syslog, DeviceLogonEvents before scheduling.

Required telemetry:

  • Syslog, DeviceLogonEvents

KQL

let FailureThreshold = 20;
let WindowMinutes = 10m;
let LookbackPeriod = 1d;
let SSHFailures = Syslog
| where TimeGenerated > ago(LookbackPeriod)
| where ProcessName == "sshd"
| where SyslogMessage has_any ("Failed password", "Invalid user", "authentication failure")
| extend RemoteIP = extract(@"from ([\d\.]+)", 1, SyslogMessage)
| where isnotempty(RemoteIP)
| where ipv4_is_private(RemoteIP) == false
| summarize
    FailureCount = count(),
    FirstFailure = min(TimeGenerated),
    LastFailure = max(TimeGenerated)
    by RemoteIP, HostName
| where FailureCount >= FailureThreshold
| where (LastFailure - FirstFailure) <= WindowMinutes
| extend BurstDurationMinutes = datetime_diff('minute', LastFailure, FirstFailure);
let SSHSuccess = DeviceLogonEvents
| where TimeGenerated > ago(LookbackPeriod)
| where ActionType == "LogonSuccess"
| where LogonType == "Network"
| where isnotempty(RemoteIP)
| where ipv4_is_private(RemoteIP) == false
| project SuccessTime = TimeGenerated, RemoteIP, SuccessDeviceName = DeviceName;
SSHFailures
| join kind=leftouter SSHSuccess on RemoteIP
| extend TimeDeltaMinutes = iff(isnotempty(SuccessTime), datetime_diff('minute', SuccessTime, LastFailure), int(null))
| where isempty(SuccessTime) or SuccessTime > LastFailure
| project
    HostName,
    RemoteIP,
    FailureCount,
    FirstFailure,
    LastFailure,
    BurstDurationMinutes,
    SuccessTime,
    SuccessDeviceName,
    TimeDeltaMinutes
| order by FailureCount desc

False Positives / Tuning / Risks / Caveats

Expected false positives:

  • Legitimate penetration testing or vulnerability scanning from authorized external IPs will trigger this detection.
  • Honeypot or canary SSH services (including Cowrie deployments) will generate high failure counts by design; if Cowrie logs are forwarded to Syslog, they will appear as real failures.
  • Internet-facing SSH servers in high-exposure environments may see baseline scanning volumes that exceed the threshold without any targeted exploitation.

Tuning notes:

  • Increase FailureThreshold above 20 in environments with high baseline SSH scanning noise; consider baselining the 95th percentile of per-IP failure counts over 7 days to set an environment-appropriate threshold.
  • Extend WindowMinutes to 30m or 1h to detect slower distributed scanning patterns.
  • Add a HostName exclusion list for known honeypot or canary hosts to prevent Cowrie-generated events from triggering production alerts.
  • If DeviceLogonEvents does not reliably capture SSH successes on Linux, consider using Syslog itself to detect success events by filtering for ‘Accepted password’ or ‘Accepted publickey’ messages as an alternative success signal.

Risks / caveats:

  • Syslog ingestion from Linux hosts requires the Log Analytics agent (MMA) or Azure Monitor Agent (AMA) with a syslog data collection rule configured for the auth or authpriv facility; without this, the Syslog table will contain no sshd entries.
  • DeviceLogonEvents is a Defender XDR / Defender for Endpoint table; it requires MDE to be deployed on the Linux hosts in scope. SSH logon telemetry in DeviceLogonEvents for Linux hosts may not be available in all MDE versions or configurations.
  • LogonType in DeviceLogonEvents for Linux SSH sessions may not consistently be populated as ‘Network’; this value should be validated against actual MDE Linux telemetry before relying on it as a filter.
  • The ipv4_is_private() function correctly identifies RFC1918 addresses but will not exclude link-local (169.254.x.x) or loopback (127.x.x.x) addresses; these are unlikely in SyslogMessage RemoteIP fields but should be noted.

Triage Runbook

First 15 minutes:

  • Confirm the source IP is external and not an approved scanner, vulnerability management tool, or internal admin network.
  • Check whether the target host is internet-facing and whether the failure burst is concentrated on one host or spread across multiple hosts.
  • Look for any successful SSH logon after the failure burst and note the time delta.
  • Validate whether the host is a honeypot, lab system, or Cowrie deployment that would intentionally generate failures.

Evidence to collect:

  • HostName, RemoteIP, FailureCount, FirstFailure, LastFailure, BurstDurationMinutes, SuccessTime, SuccessDeviceName, TimeDeltaMinutes.
  • Syslog sshd messages showing failed password, invalid user, or authentication failure events.
  • DeviceLogonEvents or equivalent SSH success telemetry for the same host and source IP.
  • Asset context for the host: exposure to the internet, criticality, and whether it is a honeypot or test system.

Pivot points:

  • Syslog for the same HostName and RemoteIP to review the full sequence of failed and accepted SSH attempts.
  • DeviceLogonEvents filtered on RemoteIP or DeviceName to identify any successful logons following the burst.
  • Network/security telemetry for the host to determine whether the IP touched other services or ports.
  • Asset inventory or CMDB to confirm whether the host is production, lab, or a monitored decoy.

Benign explanations:

  • Authorized penetration testing or vulnerability scanning from a known external IP.
  • Baseline internet noise against exposed SSH services, especially on high-visibility hosts.
  • Cowrie or other honeypot activity if the host is intentionally designed to attract scans.

Escalation criteria:

  • A successful SSH login follows the failure burst from the same IP or a related source.
  • The target host is a critical production system and the source IP is not approved.
  • Multiple hosts show the same pattern, suggesting coordinated scanning or exploitation.
  • There is evidence of post-login activity, new accounts, or configuration changes on the host.

Containment actions:

  • Block the source IP at the perimeter if it is clearly malicious and not part of an approved scan.
  • Temporarily restrict SSH exposure to trusted management networks if the host is critical and under active attack.
  • Increase monitoring on the host for additional authentication attempts and post-login activity.
  • If compromise is suspected, isolate the host from the network pending forensic review.

Closure criteria:

  • The source IP is confirmed as authorized scanning or benign internet noise.
  • No successful logon or post-authentication activity is found on the host.
  • The host is identified as a honeypot or lab system and the alert is expected.
  • The failure pattern does not exceed the environment’s established baseline after review.



Pre-Deployment Checklist by Dependency Type

Telemetry availability:

  • SSH Exploitation Scanning Spike Targeting Linux Hosts - CVE-2026-123158: Environment-specific telemetry or field mapping must be resolved for Both: Syslog, DeviceLogonEvents before scheduling.

Shared-table notes:

  • AuditLogs: shared by OAuth App Permission Grant Followed by Anomalous Service Principal Sign-In; Service Principal Sign-In Spike from New IP After OAuth App Activity - Storm-3358 Pattern
  • SigninLogs: shared by OAuth App Permission Grant Followed by Anomalous Service Principal Sign-In; Service Principal Sign-In Spike from New IP After OAuth App Activity - Storm-3358 Pattern

Sequenced Deployment Plan

  1. Start with production candidates that have no gate-level blockers: OAuth App Permission Grant Followed by Anomalous Service Principal Sign-In; Service Principal Sign-In Spike from New IP After OAuth App Activity - Storm-3358 Pattern.
  2. Resolve environment-mapping detections next: SSH Exploitation Scanning Spike Targeting Linux Hosts - CVE-2026-123158.

Hunting Agenda and Promotion Criteria

  • SSH Exploitation Scanning Spike Targeting Linux Hosts - CVE-2026-123158: Environment-specific telemetry or field mapping must be resolved for Both: Syslog, DeviceLogonEvents before scheduling.; baseline expected benign activity and define an alert-volume threshold.

Unique Blind Spot Callout

No unique blind spot was isolated beyond the detection-specific gates above.



Generated by DevSecOpsDadAttack threat intelligence and detection engineering. Validate detections before deployment.

Share: X (Twitter) LinkedIn