Agent Foskett Case File • Microsoft Entra ID • Service Principals • Microsoft Graph • Workload Identity • KQL

One Service Principal Made 6,000 API Calls Before Breakfast

There was no suspicious user sign-in.

No impossible travel.
No MFA prompt.
No interactive session at all.

Instead, one application identity had become extraordinarily busy.

Before most of the SOC had started work, a single service principal had made more than 6,000 Microsoft Graph requests.

That number looked dramatic.

But Agent Foskett knew volume alone was not a verdict.

Was this expected automation — or had a workload identity become the attacker?

Agent Foskett investigating abnormal Microsoft Graph activity from a Microsoft Entra service principal
No User. Thousands of Requests.

Workload identities authenticate without a person sitting at a keyboard. Their behaviour still leaves evidence.

✓ Identify the service principal
✓ Measure the API activity
✓ Determine what the application actually accessed

6,000 calls sounded suspicious — but was it?

A backup product, provisioning system, monitoring platform or integration can legitimately make thousands of API requests.

So Agent Foskett did not begin with the assumption that high volume meant compromise.

He began with a baseline question.

Was this volume normal for this service principal?

Find the busiest service principals

Microsoft documents AADServicePrincipalSignInLogs for service-principal sign-ins. Agent Foskett first ranked workload identities by recent authentication activity to identify whether the application was unusually active compared with its peers.
most-active-service-principals.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
AADServicePrincipalSignInLogs
| where TimeGenerated > ago(1d)
| summarize SignInCount = count(),
            FirstSeen = min(TimeGenerated),
            LastSeen = max(TimeGenerated),
            SourceIPs = make_set(IPAddress, 20)
    by ServicePrincipalId,
       ServicePrincipalName,
       AppId
| order by SignInCount desc

Authentication was only half the story

A service-principal sign-in tells you that a workload identity authenticated to a resource.

It does not automatically tell you every Microsoft Graph operation performed with the resulting token.

For that, Agent Foskett moved to Microsoft Graph activity telemetry.

Authentication answers how the workload got in. API activity answers what it did next.

Count the Microsoft Graph requests

Where Microsoft Graph activity logs were being collected, MicrosoftGraphActivityLogs exposed HTTP requests made against tenant resources. Agent Foskett grouped the activity by application and service principal rather than assuming the 6,000-call headline was meaningful by itself.
graph-request-volume.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
MicrosoftGraphActivityLogs
| where TimeGenerated > ago(1d)
| summarize Requests = dcount(RequestId),
            FirstRequest = min(TimeGenerated),
            LastRequest = max(TimeGenerated),
            Methods = make_set(RequestMethod, 10),
            StatusCodes = make_set(ResponseStatusCode, 20)
    by AppId,
       ServicePrincipalId
| order by Requests desc

The volume was new

The service principal was normally active, but not like this.

Its request volume had jumped sharply compared with previous days.

The time window was unusual.
The endpoints were different.
And write operations appeared where the workload normally performed reads.

The anomaly was not simply “6,000”. It was 6,000 requests that did not look like this identity's normal job.

Find what the application was calling

Agent Foskett then broke the requests down by method and URI. The aim was to distinguish repetitive expected reads from access to sensitive or unusual Microsoft Graph resources.
graph-endpoints.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
let TargetServicePrincipal =
    "00000000-0000-0000-0000-000000000000";
MicrosoftGraphActivityLogs
| where TimeGenerated > ago(1d)
| where ServicePrincipalId == TargetServicePrincipal
| extend ResourcePath =
    tostring(parse_url(RequestUri).Path)
| summarize Requests = dcount(RequestId),
            Successes = countif(ResponseStatusCode between (200 .. 299)),
            Failures = countif(ResponseStatusCode >= 400)
    by RequestMethod,
       ResourcePath
| order by Requests desc

Reads and writes changed the meaning of the investigation

Thousands of repeated GET requests to an expected endpoint could be inefficient automation.

POST, PATCH, PUT or DELETE activity against unexpected resources deserved a different level of attention.

Agent Foskett therefore separated volume from capability and capability from actual use.

What an application can do matters. What it actually did matters more.

Inspect successful write operations

The next query isolated successful non-read operations from the service principal. This did not label them malicious; it created the set of actions that needed business and security validation.
graph-write-activity.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
let TargetServicePrincipal =
    "00000000-0000-0000-0000-000000000000";
MicrosoftGraphActivityLogs
| where TimeGenerated > ago(1d)
| where ServicePrincipalId == TargetServicePrincipal
| where RequestMethod in ("POST", "PATCH", "PUT", "DELETE")
| where ResponseStatusCode between (200 .. 299)
| project TimeGenerated,
          AppId,
          ServicePrincipalId,
          RequestMethod,
          RequestUri,
          ResponseStatusCode,
          RequestId,
          SignInActivityId,
          Roles,
          Scopes
| order by TimeGenerated asc

Permissions explained possibility — not intent

The Graph activity included token context such as roles and scopes where available.

Agent Foskett compared those claims with the application's intended purpose and its Entra configuration.

A powerful application permission could explain how the operation was authorised.

It could not explain why the operation happened.

Authorization tells you what the workload was allowed to do. Investigation tells you whether the behaviour made sense.

Correlate Graph activity with workload authentication

Microsoft documents linkable identifiers between Microsoft Graph activity and sign-in telemetry. Agent Foskett used the Graph SignInActivityId and the sign-in log's UniqueTokenIdentifier to correlate API activity with authentication evidence where a matching record existed.
graph-to-service-principal-signin.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
let TargetServicePrincipal =
    "00000000-0000-0000-0000-000000000000";
MicrosoftGraphActivityLogs
| where TimeGenerated > ago(4d)
| where ServicePrincipalId == TargetServicePrincipal
| join kind=leftouter (
    AADServicePrincipalSignInLogs
    | where TimeGenerated > ago(4d)
    | project SignInTime = TimeGenerated,
              ServicePrincipalId,
              ServicePrincipalName,
              IPAddress,
              ResourceDisplayName,
              ResultType,
              UniqueTokenIdentifier
)
on $left.SignInActivityId == $right.UniqueTokenIdentifier
| project TimeGenerated,
          SignInTime,
          ServicePrincipalName,
          AppId,
          ServicePrincipalId,
          IPAddress,
          RequestMethod,
          RequestUri,
          ResponseStatusCode,
          SignInActivityId
| order by TimeGenerated asc

Not every Graph request will necessarily have a matching sign-in row

Agent Foskett treated correlation carefully.

Microsoft notes that some Microsoft Graph activity does not have a corresponding service-principal sign-in record, including some first-party app-only activity.

A missing join therefore was not automatically proof of log loss or evasion.

Correlation gaps need interpretation, not assumptions.

Now ask what changed

The service principal had existed for months.

So why had its behaviour changed today?

Agent Foskett reviewed recent application-management events, credential changes, permission grants and ownership changes around the workload identity.

He also checked whether the source IPs and authentication pattern were consistent with the system that normally used the application.

A long-lived application can become dangerous when its credentials, permissions or operator change.

Do not confuse a service principal with a user

There was no employee to interview about the sign-in.

No MFA challenge to inspect in the normal user sense.

No desktop session to reconstruct.

The investigation had to follow workload evidence: application identity, credentials, permissions, source addresses, target resources and API operations.

Workload identities require workload investigation techniques.

Build the workload-identity timeline

Activity spike beginsA normally predictable service principal suddenly becomes unusually active.
Authentication reviewedAADServicePrincipalSignInLogs establishes workload sign-ins, source addresses and target resources.
Graph requests measuredMicrosoftGraphActivityLogs shows the scale and timing of API activity.
Endpoints classifiedExpected reads are separated from unusual resources and write operations.
Permissions validatedRoles, scopes and application configuration are compared with the workload's intended purpose.
Cause investigatedCredential, permission, owner and source changes are examined to explain the behavioural shift.

What Agent Foskett checked

Service principalWhich workload identity generated the activity?
Request volumeWas 6,000 actually abnormal for this application?
Source IPsDid authentication originate from expected infrastructure?
Graph endpointsWhich tenant resources were queried or modified?
Methods and responsesWere the requests reads, writes, successful operations or repeated failures?
Permissions and changesDid the application's privileges, credentials or ownership recently change?

What the evidence can and cannot prove

AADServicePrincipalSignInLogs can show service-principal authentication activity when that telemetry is collected.

MicrosoftGraphActivityLogs can show Microsoft Graph requests and fields such as application ID, service-principal ID, request URI, method and response status when Graph activity logging is enabled and routed to the workspace.

High request volume alone does not prove compromise.

Successful API operations alone do not prove malicious intent.

The conclusion comes from behaviour, permissions, business purpose, authentication context and the actual resources touched.

The lesson

The service principal did not look like a traditional attacker.

It had no mailbox.
No keyboard.
No human session.

But it had an identity, credentials and permission to call Microsoft Graph.

And once its behaviour changed, those permissions mattered.

Workload identities do not need to look human to become part of an attack.
Investigation principle: Baseline service principals by what they normally authenticate to and what APIs they normally call. Investigate changes in behaviour, not merely large numbers.
No user. Thousands of requests.
Find the workload identity. Measure the behaviour. Follow the API activity.
Continue the Investigation

Final thought

Security teams naturally notice people.

Users sign in.
Users click links.
Users run processes.

But applications authenticate too.

Service principals can hold powerful permissions and operate continuously without anybody sitting in front of a screen.

Six thousand API calls were not the answer.

They were the clue that told Agent Foskett where to start looking.

The Logs Already Knew! 🔎
Develop IT.. Protect IT.. GEMXIT.
GEMXIT PTY LTD | GEMXIT UK LTD
Talk to GEMXIT

One Service Principal Made 6,000 API Calls Before Breakfast

This Agent Foskett investigation examines abnormal Microsoft Entra service-principal behaviour using AADServicePrincipalSignInLogs, MicrosoftGraphActivityLogs and KQL.

Investigating Service Principal Activity

Measure workload authentication, Microsoft Graph API request volume, source addresses, request methods, endpoints, permissions and changes to determine whether unusual application activity is legitimate automation or a security incident.

Microsoft Graph Activity Logs and Workload Identities

Learn how Microsoft Graph activity can be correlated with Microsoft Entra sign-in telemetry and why workload identities require behavioural baselines that reflect what each application normally does.