Detect Confluence in Sumo Logic CSE
Adversaries may leverage Confluence repositories to mine valuable information. Often found in development environments alongside Atlassian JIRA, Confluence is generally used to store development-related documentation but may contain diverse categories of sensitive information including: policies and procedures, physical/logical network diagrams, system architecture diagrams, technical system documentation, testing/development credentials, work/project schedules, source code snippets, and links to internal resources. LAPSUS$ is documented to have specifically searched victim Confluence and JIRA instances to discover high-privilege account credentials as part of their data theft operations, making this a high-value target during the collection phase of an intrusion.
MITRE ATT&CK
- Tactic
- Collection
- Technique
- T1213 Data from Information Repositories
- Sub-technique
- T1213.001 Confluence
- Canonical reference
- https://attack.mitre.org/techniques/T1213/001/
Sumo Detection Query
_sourceCategory=atlassian/confluence OR _sourceCategory=atlassian/audit
| json field=_raw "type" as event_type nodrop
| json field=_raw "eventType" as event_type2 nodrop
| json field=_raw "action" as action nodrop
| json field=_raw "author.publicName" as author_name nodrop
| json field=_raw "author" as author2 nodrop
| json field=_raw "username" as username nodrop
| json field=_raw "remoteAddress" as remote_ip nodrop
| json field=_raw "remote_address" as remote_ip2 nodrop
| json field=_raw "content.title" as page_title nodrop
| json field=_raw "pageTitle" as page_title2 nodrop
| json field=_raw "space.key" as space_key nodrop
| json field=_raw "spaceKey" as space_key2 nodrop
| json field=_raw "searchQuery" as search_query nodrop
| json field=_raw "query" as search_query2 nodrop
| where !(isNull(event_type) && isNull(event_type2) && isNull(action))
| if (!isNull(event_type), event_type, if (!isNull(event_type2), event_type2, action)) as eff_event_type
| if (!isNull(author_name), author_name, if (!isNull(author2), author2, username)) as eff_user
| if (!isNull(remote_ip), remote_ip, remote_ip2) as eff_ip
| if (!isNull(page_title), page_title, page_title2) as eff_title
| if (!isNull(space_key), space_key, space_key2) as eff_space
| if (!isNull(search_query), search_query, search_query2) as eff_query
| toLowerCase(eff_event_type) as eff_event_type
| toLowerCase(eff_query) as eff_query
| if (eff_event_type matches ".*(?:view|viewed|read).*", 1, 0) as is_view
| if (eff_event_type matches ".*search.*", 1, 0) as is_search
| if (eff_event_type matches ".*(?:export|print|pdf|download).*", 1, 0) as is_export
| if (is_search = 1 AND (eff_query matches ".*(?:password|passwd|credential|secret|api.?key|apikey|token|vpn|ssh|private.?key|aws|azure|gcp|bearer|ldap|kerberos|connection.?string|access.?key|service.?account).*"), 1, 0) as is_sensitive_search
| timeslice 1h
| stats
count as TotalActions,
sum(is_view) as PageViews,
sum(is_search) as Searches,
sum(is_export) as Exports,
sum(is_sensitive_search) as SensitiveSearches,
countDistinct(eff_space) as UniqueSpaces,
countDistinct(eff_title) as UniquePages,
first(_messageTime) as FirstActivity,
last(_messageTime) as LastActivity
by eff_user, eff_ip, _timeslice
| (LastActivity - FirstActivity) / 60000 as DurationMs
| if (DurationMs < 60000, 1, DurationMs / 60000) as DurationMinutes
| TotalActions / DurationMinutes as AccessRatePerMin
| round(AccessRatePerMin, 2) as AccessRatePerMin
| if (TotalActions > 40, 1, 0) as BulkAccess
| if (AccessRatePerMin > 10, 1, 0) as AutomatedScraping
| if (UniqueSpaces > 5, 1, 0) as MultiSpaceEnum
| if (SensitiveSearches > 0, 1, 0) as CredentialHunting
| if (Exports > 5, 1, 0) as BulkExport
| BulkAccess + AutomatedScraping + MultiSpaceEnum + CredentialHunting + BulkExport as RiskScore
| where RiskScore > 0
| if (AutomatedScraping = 1,
concat("Automated scraping — ", toString(AccessRatePerMin), " pages/min"),
if (CredentialHunting = 1,
concat("Credential hunting — ", toString(SensitiveSearches), " sensitive searches"),
if (BulkExport = 1,
concat("Bulk export — ", toString(Exports), " exports"),
if (MultiSpaceEnum = 1,
concat("Multi-space enumeration — ", toString(UniqueSpaces), " spaces"),
concat("High-volume bulk access — ", toString(TotalActions), " actions")
)
)
)
) as ThreatIndicator
| fields _timeslice, eff_user, eff_ip, TotalActions, UniquePages, UniqueSpaces, Searches, SensitiveSearches, Exports, AccessRatePerMin, ThreatIndicator, RiskScore
| sort by RiskScore desc, TotalActions desc Detects T1213.001 Confluence data mining in Sumo Logic by parsing Confluence audit JSON logs and aggregating access patterns per user per hour. Applies multi-factor risk scoring across bulk access volume, automated scraping rate, multi-space enumeration, sensitive credential-hunting search queries, and bulk export activity — mirroring the reference SPL detection logic with Sumo Logic CSE operators.
Data Sources
Required Tables
False Positives & Tuning
- Atlassian Confluence administrators performing space exports for backup or migration generate high export counts that will exceed the threshold even in normal operations
- Content audit or governance tools that enumerate Confluence spaces and pages to enforce content lifecycle policies, producing multi-space access patterns
- Engineering teams performing disaster recovery drills or documentation audits where members simultaneously access many spaces and pages in a short window
Other platforms for T1213.001
Testing Methodology
Validate this detection against 4 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1Confluence Space Enumeration via REST API
Expected signal: GET request to /rest/api/space visible in proxy logs with source host, user agent, and response bytes. Atlassian audit log records an API access event for the authenticated user. CloudAppEvents (if MCAS integrated) captures SpaceViewed or API access events per space returned.
- Test 2Confluence Credential Hunting via Search API (CQL)
Expected signal: Multiple GET requests to /rest/api/content/search with credential-related CQL query parameters visible in proxy logs and URL paths. Atlassian audit log records each SearchPerformed event with the query text. CloudAppEvents captures SearchPerformed events; the SensitiveSearchCount metric in the primary KQL query increments for each sensitive term.
- Test 3Bulk Page Content Extraction with Body Storage Expansion
Expected signal: GET request to /rest/api/content with expand=body.storage parameter in proxy logs. Significantly higher bytes-transferred value than a standard metadata-only request due to full page bodies. Atlassian audit log records content access events. File created in /tmp on attacker system.
- Test 4Confluence Space XML Export via Web Interface
Expected signal: POST to /dologin.action followed by GET to /spaces/exportspacezipxml.action visible in proxy logs. Large file download (ZIP archive) with high bytes-transferred. Atlassian audit log records a space export event under the authenticated user. CASB/MCAS captures SpaceExported or ContentExported event.
References (8)
- https://attack.mitre.org/techniques/T1213/001/
- https://confluence.atlassian.com/confkb/how-to-enable-user-access-logging-182943.html
- https://www.microsoft.com/en-us/security/blog/2022/03/22/dev-0537-criminal-actor-targeting-organizations-for-data-exfiltration-and-destruction/
- https://developer.atlassian.com/cloud/confluence/rest/v1/intro/
- https://confluence.atlassian.com/doc/confluence-audit-log-1017226528.html
- https://learn.microsoft.com/en-us/defender-cloud-apps/tutorial-shadow-it
- https://learn.microsoft.com/en-us/defender-xdr/advanced-hunting-cloudappevents-table
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1213.001/T1213.001.md
Unlock Pro Content
Get the full detection package for T1213.001 including response playbook, investigation guide, and atomic red team tests.