Agent Foskett Case File • Data Exfiltration • Azure SQL • API Activity • KQL

Someone Exported the Database — But No Download Was Recorded

The customer records had appeared somewhere they should not have been.

The security team checked the file download logs.

Nothing.

They checked the usual export folders.

Nothing.

“So the data didn't leave?” someone asked.

Agent Foskett stared at the application traffic.

“That depends,” he replied, “on whether you think an export has to be a file.”

Agent Foskett investigating data extraction through application API and database activity
No Download Event Is Not an Exfiltration Verdict

Data can move through application responses, database queries and APIs without creating an ordinary file-download audit event.

✓ Follow the data path
✓ Correlate identities and database queries
✓ Distinguish evidence from assumptions

The missing export

The finance team discovered that a sample of customer records had reached an unauthorised external recipient. An internal review began immediately.

The first searches focused on familiar signals: exported spreadsheets, downloaded documents and user-driven file transfers. None explained the disclosure.

“No downloads,” the analyst said. “Maybe the data came from somewhere else.”

Agent Foskett looked at the application architecture. The customer portal queried an Azure SQL database through a backend API. It could return records as JSON directly to a client.

That response might never be written to a file on the server.

A file event was the wrong starting point

Microsoft Purview audit records can be valuable for supported Microsoft 365 workloads, including many file activities. But an Azure-hosted custom application returning rows from Azure SQL is not automatically represented as a SharePoint or OneDrive file-download event.

Agent Foskett refused to treat the absence of one type of event as proof that no data was transmitted.

He wrote three questions on the board:

Which system held the records?
Which identity was authorised to read them?
Which interface could send those records outside the trusted boundary?

The API nobody had examined

The portal supported a legitimate search endpoint. Normal requests returned a handful of customer records. But the team discovered an unusual sequence of requests using pagination parameters, each asking for the next batch.

In this illustrative case, the requests came from an unfamiliar client network and used a valid application session. The responses were successful, and the cumulative result count was far beyond an ordinary user workflow.

“One page looks innocent,” Agent Foskett said. “A thousand pages can look a lot like a database export.”

The investigation shifted from file downloads to bulk record access.

Start with application request telemetry

If the application sends request telemetry to an Application Insights workspace, AppRequests can help identify unusual request volumes, response patterns and client context. This example assumes the application has instrumented its endpoint and is sending that telemetry to the workspace.

Important: Request telemetry usually does not prove the response body contained particular records. Pagination parameters and response record counts require deliberate application logging, with appropriate privacy controls.
api-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
let EndpointFragment = "/api/customers";
AppRequests
| where TimeGenerated > ago(7d)
| where Url contains EndpointFragment
| summarize Requests=count(),
            FirstSeen=min(TimeGenerated),
            LastSeen=max(TimeGenerated),
            Failures=countif(Success == false)
    by ClientIP, Name, ResultCode
| order by Requests desc

The database saw a different story

Agent Foskett then examined Azure SQL auditing, where enabled and routed to Log Analytics. Database audit events can help establish who issued a statement, which database was accessed and what statement was recorded, subject to configuration and the audit data available.

In the case narrative, the application service identity executed repeated SELECT queries against a sensitive customer table during the same window as the API activity.

That was significant—but not enough on its own. A busy portal can legitimately perform many reads. The team needed the application route, request volume, identity and data sensitivity in the same timeline.

Hunt the Azure SQL audit trail

The following is an illustrative query for environments where Azure SQL auditing is available in the AzureDiagnostics table. Audit schemas and destinations vary: some environments use resource-specific tables, and field availability depends on configuration. Check your actual workspace schema before running it.
azure-sql-audit.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
AzureDiagnostics
| where TimeGenerated > ago(7d)
| where Category == "SQLSecurityAuditEvents"
| where action_name_s has "SELECT"
| project TimeGenerated,
          Resource,
          database_name_s,
          server_principal_name_s,
          client_ip_s,
          statement_s,
          succeeded_s
| order by TimeGenerated asc

Who was the application acting for?

The database audit trail showed the application service identity, not necessarily the human or session that triggered each API request. That distinction mattered.

A backend service may connect to SQL using a managed identity or service principal while serving hundreds of different users. Seeing that identity in a database audit record does not identify which user requested the data.

Agent Foskett asked the developers for the application correlation IDs, authenticated user IDs, route names and per-request result counts, where these had been safely recorded. The missing link was not another guess—it was application-level attribution.

Correlate the timeline, not just the timestamps

The team aligned the suspicious session, API requests, SQL reads and outbound responses using correlation identifiers where available. They accounted for processing delays, time zones, retries and normal background activity.

In this fictional investigation, the sequence was consistent: an unfamiliar session requested repeated customer pages; the backend issued corresponding SQL reads; and the API returned successful responses over the same period.

The investigation established a credible bulk-extraction path without claiming that any single telemetry source captured the full contents of each response.
09:12 — Unusual sessionAn authenticated client begins requesting customer records from an unfamiliar network.
09:14 — Repeated API pagesA normally low-volume endpoint receives sustained pagination requests.
09:15 — Database readsThe application service identity issues matching reads against the customer dataset.
09:16 — Successful responsesApplication telemetry records repeated successful requests; response contents need separate evidence.
09:34 — Activity stopsThe client ceases requests after an unusually large sequence.
Investigation escalatedCorrelated telemetry and the external disclosure justify a suspected bulk-data-extraction response.

Could the requests have been legitimate?

Agent Foskett tested the alternatives. Was a reporting job running? Had a migration been scheduled? Was an approved integration syncing customer records? Did the client IP belong to a corporate gateway? Was the same pagination pattern normal for this application?

Each explanation was checked against change records, application ownership, access permissions and expected volume.

“An unusual query is a lead,” he said. “It becomes a finding when the evidence supports it.”

What about Microsoft Purview?

Microsoft Purview auditing and data-loss-prevention capabilities can help with supported workloads and configured data paths. They are not a universal packet recorder for every custom API or Azure SQL response.

For this case, the investigators used Purview-related evidence where relevant, but relied primarily on application telemetry, database audit data, identity context and the external disclosure. The team also checked whether its DLP coverage included this particular application architecture.

Control coverage is not the same thing as data coverage.

A second KQL hunt: identify unusual bursts

For an instrumented application, request bursts can reveal candidate sessions or networks for further investigation. The threshold below is illustrative and must be tuned to real application traffic.
api-bursts.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
AppRequests
| where TimeGenerated > ago(7d)
| where Url contains "/api/customers"
| summarize Requests=count(),
            Successful=countif(Success == true)
    by ClientIP, bin(TimeGenerated, 10m)
| where Requests > 100
| order by Requests desc

What the evidence proved—and what it did not

The absence of a file-download event did not rule out data extraction. Correlated application requests and database audit records supported a mechanism by which customer data could have been returned through an API.

To establish precisely which records left, the team would need additional trustworthy evidence, such as privacy-conscious response-count logging, transaction records, verified recipient samples or other application-specific audit data.

Likewise, the database service identity alone did not establish the initiating user. The investigation needed the application’s authentication and correlation trail.

Contain the exposure

The response team preserved application, identity and database audit evidence; reviewed the suspicious account or token; assessed API authorisation; and restricted bulk access while protecting legitimate customer operations.

They considered rate limiting, query limits, pagination caps, least-privilege database access, anomaly detection and better logging of high-volume data access—without logging sensitive response bodies unnecessarily.

They also assessed legal, contractual and regulatory notification obligations based on confirmed exposure and the organisation’s jurisdiction.

The lesson

A security team can search every download log it has and still miss a data-extraction path it never instrumented.

Files are one way data moves. APIs are another.

The correct investigation follows the application architecture, the identity, the database activity and the outbound response—not just the event name an analyst expected to find.

Investigation principle: The absence of a particular audit event is meaningful only when that event source actually covers the activity under investigation.
No download event. Plenty of evidence.
Investigate the API, identity and database trail before drawing conclusions.
Explore More Investigations

Final thought

“No file was downloaded,” the analyst said.

Agent Foskett nodded.

“Quite possibly.”

“Then how did the customer data leave?”

He pointed at the API request timeline.

“One response at a time.”

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

Someone Exported the Database — But No Download Was Recorded

Agent Foskett investigates a fictional data exfiltration scenario involving application APIs, Azure SQL and missing file-download records.

API Data Exfiltration Investigation with KQL

Hunt unusual API request volume with AppRequests and examine Azure SQL audit records where auditing is enabled and available.

Microsoft Security Investigation

Correlate application request context, database audit events, user identity and response telemetry without treating missing file events as proof that no data left.