Panther medium experimental python

Salesforce Bulk API Data Exfiltration

Detects Salesforce Bulk API operations that could indicate data exfiltration attempts. The Bulk API allows users to process large volumes of records (up to millions) asynchronously, making it a common vector for data theft. This detection triggers on all Bulk API job completions and adjusts severity based on: - Operation type (query operations are highest risk for exfiltration) - Volume of records processed - Entity/object type being accessed

View Source

Detection Logic

def rule(event):
    # Alert on Salesforce Bulk API Result Events
    # These events are generated when bulk API jobs complete
    # and can indicate large-scale data exfiltration attempts
    return event.get("EVENT_TYPE") == "BulkApiResultEventStore"


def title(event):
    # Create descriptive title with operation and volume details
    user = event.get("USER_NAME", event.get("USER_ID", "<UNKNOWN_USER>"))
    operation = event.get("OPERATION_TYPE", "<UNKNOWN_OPERATION>")
    records = event.get("RECORDS_PROCESSED", 0)
    entity = event.get("ENTITY_NAME", "<UNKNOWN_ENTITY>")

    return f"Salesforce Bulk API: {operation} on {entity} ({records:,} records) - User: {user}"


def severity(event):
    # Map based on operation type and volume
    operation = event.get("OPERATION_TYPE", "")
    records = event.get("RECORDS_PROCESSED", 0)
    # Ensure records is numeric
    records = records if isinstance(records, (int, float)) else 0

    # Query operations are most concerning for data exfiltration
    if operation in ["query", "queryAll"]:
        if records >= 100000:
            severity_level = "CRITICAL"
        elif records >= 50000:
            severity_level = "HIGH"
        elif records >= 10000:
            severity_level = "MEDIUM"
        else:
            severity_level = "DEFAULT"
    # Other operations (insert, update, delete) are also notable
    elif operation in ["delete", "hardDelete"]:
        if records >= 10000:
            severity_level = "HIGH"
        elif records >= 1000:
            severity_level = "MEDIUM"
        else:
            severity_level = "DEFAULT"
    # Default for other operations
    else:
        if records >= 50000:
            severity_level = "HIGH"
        elif records >= 10000:
            severity_level = "MEDIUM"
        else:
            severity_level = "DEFAULT"

    return severity_level


def dedup(event):
    # Deduplicate by job ID to avoid duplicate alerts for the same job
    job_id = event.get("JOB_ID", "unknown")
    return f"SF_BULK_API_{job_id}"


def alert_context(event):
    # Provide comprehensive context for investigation
    return {
        "Job ID": event.get("JOB_ID"),
        "User ID": event.get("USER_ID"),
        "Username": event.get("USER_NAME"),
        "Operation Type": event.get("OPERATION_TYPE"),
        "Entity Name": event.get("ENTITY_NAME"),
        "Records Processed": event.get("RECORDS_PROCESSED"),
        "Number of Batches": event.get("NUMBER_OF_BATCHES"),
        "API Version": event.get("API_VERSION"),
        "Source IP": event.get("SOURCE_IP"),
        "Request ID": event.get("REQUEST_ID"),
        "Organization ID": event.get("ORGANIZATION_ID"),
        "Job Type": event.get("JOB_TYPE"),
    }

Field Validations

Loading…

Comments (0)

Loading comments...