Detection rules › Panther

AWS S3 Large Download

Tags
Beta, Data Exfiltration
Source
github.com/panther-labs/panther-analysis

Returns S3 GetObject events where a user has downloaded more than the configured threshold of data within the specified time window. Supports filtering by bucket patterns and user types.

Rules detecting the same action

Other rules on this platform that filter on the same API call or operation.

Rule body yaml

AnalysisType: scheduled_query
QueryName: "AWS S3 Large Download"
Enabled: false
Description: >
  Returns S3 GetObject events where a user has downloaded more than the configured threshold 
  of data within the specified time window. Supports filtering by bucket patterns and user types.
Tags:
  - Beta
  - Data Exfiltration
Query: |-
  SELECT 
    userIdentity:arn as user_arn,
    COALESCE(userIdentity:userName, userIdentity:sessionContext:sessionIssuer:userName, 'unknown') as user_name,
    userIdentity:type as user_type,
    requestParameters:bucketName as bucket_name,
    sourceIPAddress as source_ip,
    userAgent as user_agent,
    SUM(COALESCE(additionalEventData:bytesTransferredOut::int, 0)) as total_bytes_downloaded,
    COUNT(*) as object_count,
    MIN(p_event_time) as first_download_time,
    MAX(p_event_time) as last_download_time,
    ARRAY_AGG(DISTINCT requestParameters:key) as sample_objects
  FROM panther_logs.public.aws_cloudtrail
  WHERE eventName = 'GetObject'
    AND eventSource = 's3.amazonaws.com'
    AND userIdentity:type IN ('IAMUser', 'AssumedRole', 'FederatedUser')
    AND errorCode IS NULL
    AND p_event_time >= DATEADD(minute, -10, CURRENT_TIMESTAMP())
    AND userIdentity:arn NOT LIKE '%panther-snowflake-api%'
    -- AND (requestParameters:bucketName LIKE '%sensitive%' OR requestParameters:bucketName LIKE '%prod%')
  GROUP BY 
    userIdentity:arn,
    COALESCE(userIdentity:userName, userIdentity:sessionContext:sessionIssuer:userName, 'unknown'),
    userIdentity:type,
    requestParameters:bucketName,
    sourceIPAddress,
    userAgent
  HAVING SUM(COALESCE(additionalEventData:bytesTransferredOut::int, 0)) >= 52428800  -- 50MB default
  ORDER BY total_bytes_downloaded DESC
Schedule:
  RateMinutes: 10
  TimeoutMinutes: 3

Detection logic

Stage 1: source

panther_logs.public.aws_cloudtrail

Stage 2: filter

eventName eq "GetObject"
eventSource eq "s3.amazonaws.com"
userIdentity:type in ["IAMUser", "AssumedRole", "FederatedUser"]
errorCode is_null
userIdentity:arn not wildcard "*panther-snowflake-api*"

This rule also runs imperative logic the parser cannot express as a filter; the conditions above are the structured part it could extract.

Stage 3: having

Threshold
ge 52428800

Exclusions

Top-level NOT(...) conjuncts: predicates this rule actively suppresses.

FieldKindExcluded values
userIdentity:arnmatchpanther-snowflake-api

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
errorCodeis_null
  • (no value, null check)
eventNameeq
  • GetObject
eventSourceeq
  • s3.amazonaws.com
userIdentity:typein
  • AssumedRole
  • FederatedUser
  • IAMUser

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
user_arnuserIdentity:arn
user_nameCOALESCE ( userIdentity:userName , userIdentity:sessionContext:sessionIssuer:userName , 'unknown' )
user_typeuserIdentity:type
bucket_namerequestParameters:bucketName
source_ipsourceIPAddress
user_agentuserAgent
total_bytes_downloadedSUM ( COALESCE ( additionalEventData:bytesTransferredOut : : int , 0 ) )
object_countCOUNT ( * )
first_download_timeMIN ( p_event_time )
last_download_timeMAX ( p_event_time )
sample_objectsARRAY_AGG ( DISTINCT requestParameters:key )