AWS S3 Static Site JavaScript File Uploaded

This rule detects when a JavaScript file is uploaded or accessed in an S3 static site directory (static/js/) by an IAM user or assumed role. This can indicate suspicious modification of web content hosted on S3, such as injecting malicious scripts into a static website frontend.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2025/04/15"
  3integration = ["aws"]
  4maturity = "production"
  5updated_date = "2025/07/16"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10This rule detects when a JavaScript file is uploaded or accessed in an S3 static site directory (`static/js/`) by an IAM
 11user or assumed role. This can indicate suspicious modification of web content hosted on S3, such as injecting malicious
 12scripts into a static website frontend.
 13"""
 14false_positives = [
 15    """
 16    Development or deployment pipelines that update static frontends frequently (e.g., React/Vue apps) may trigger this.
 17    Verify the user agent, source IP, and whether the modification was expected.
 18    """,
 19]
 20from = "now-9m"
 21language = "esql"
 22license = "Elastic License v2"
 23name = "AWS S3 Static Site JavaScript File Uploaded"
 24note = """## Triage and Analysis
 25
 26### Investigating AWS S3 Static Site JavaScript File Uploaded
 27
 28An S3 `PutObject` action that targets a path like `static/js/` and uploads a `.js` file is a potential signal for web content modification. If done by an unexpected IAM user or outside of CI/CD workflows, it may indicate a compromise.
 29
 30#### Possible Investigation Steps
 31
 32- **Identify the Source User**: Check `aws.cloudtrail.user_identity.arn`, access key ID, and session type (`IAMUser`, `AssumedRole`, etc).
 33- **Review File Content**: Use the S3 `GetObject` or CloudTrail `requestParameters` to inspect the uploaded file for signs of obfuscation or injection.
 34- **Correlate to Other Events**: Review events from the same IAM user before and after the upload (e.g., `ListBuckets`, `GetCallerIdentity`, IAM activity).
 35- **Look for Multiple Uploads**: Attackers may attempt to upload several files or modify multiple directories.
 36
 37### False Positive Analysis
 38
 39- This behavior may be expected during app deployments. Look at:
 40  - The `user_agent.original` to detect legitimate CI tools (like Terraform or GitHub Actions).
 41  - Timing patterns—does this match a regular release window?
 42  - The origin IP and device identity.
 43
 44### Response and Remediation
 45
 46- **Revert Malicious Code**: Replace the uploaded JS file with a clean version and invalidate CloudFront cache if applicable.
 47- **Revoke Access**: If compromise is confirmed, revoke the IAM credentials and disable the user.
 48- **Audit IAM Policies**: Ensure that only deployment users can modify static site buckets.
 49- **Enable Bucket Versioning**: This can allow for quick rollback and historical review.
 50"""
 51references = [
 52    "https://www.sygnia.co/blog/sygnia-investigation-bybit-hack/",
 53    "https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteHosting.html",
 54    "https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html",
 55]
 56risk_score = 47
 57rule_id = "16acac42-b2f9-4802-9290-d6c30914db6e"
 58severity = "medium"
 59tags = [
 60    "Domain: Cloud",
 61    "Data Source: AWS",
 62    "Data Source: Amazon Web Services",
 63    "Data Source: AWS S3",
 64    "Tactic: Impact",
 65    "Use Case: Web Application Compromise",
 66    "Use Case: Cloud Threat Detection",
 67    "Resources: Investigation Guide",
 68]
 69timestamp_override = "event.ingested"
 70type = "esql"
 71
 72query = '''
 73from logs-aws.cloudtrail* metadata _id, _version, _index
 74
 75| where
 76    // S3 object read/write activity
 77    event.dataset == "aws.cloudtrail"
 78    and event.provider == "s3.amazonaws.com"
 79    and event.action in ("GetObject", "PutObject")
 80
 81    // IAM users or assumed roles only
 82    and aws.cloudtrail.user_identity.type in ("IAMUser", "AssumedRole")
 83
 84    // Requests for static site bundles
 85    and aws.cloudtrail.request_parameters like "*static/js/*.js*"
 86
 87    // Exclude IaC and automation tools
 88    and not (
 89        user_agent.original like "*Terraform*"
 90        or user_agent.original like "*Ansible*"
 91        or user_agent.original like "*Pulumni*"
 92    )
 93
 94// Extract fields from request parameters
 95| dissect aws.cloudtrail.request_parameters
 96    "%{{?bucket.name.key}=%{Esql.aws_cloudtrail_request_parameters_bucket_name}, %{?host.key}=%{Esql_priv.aws_cloudtrail_request_parameters_host}, %{?bucket.object.location.key}=%{Esql.aws_cloudtrail_request_parameters_bucket_object_location}}"
 97
 98// Extract file name portion from full object path
 99| dissect Esql.aws_cloudtrail_request_parameters_object_location "%{}static/js/%{Esql.aws_cloudtrail_request_parameters_object_key}"
100
101// Match on JavaScript files
102| where ends_with(Esql.aws_cloudtrail_request_parameters_object_key, ".js")
103
104// Retain relevant ECS and dissected fields
105| keep
106    aws.cloudtrail.user_identity.arn,
107    aws.cloudtrail.user_identity.access_key_id,
108    aws.cloudtrail.user_identity.type,
109    aws.cloudtrail.request_parameters,
110    Esql.aws_cloudtrail_request_parameters_bucket_name,
111    Esql.aws_cloudtrail_request_parameters_object_key,
112    user_agent.original,
113    source.ip,
114    event.action,
115    @timestamp
116'''
117
118
119[[rule.threat]]
120framework = "MITRE ATT&CK"
121[[rule.threat.technique]]
122id = "T1565"
123name = "Data Manipulation"
124reference = "https://attack.mitre.org/techniques/T1565/"
125[[rule.threat.technique.subtechnique]]
126id = "T1565.001"
127name = "Stored Data Manipulation"
128reference = "https://attack.mitre.org/techniques/T1565/001/"
129
130
131
132[rule.threat.tactic]
133id = "TA0040"
134name = "Impact"
135reference = "https://attack.mitre.org/tactics/TA0040/"

Triage and Analysis

Investigating AWS S3 Static Site JavaScript File Uploaded

An S3 PutObject action that targets a path like static/js/ and uploads a .js file is a potential signal for web content modification. If done by an unexpected IAM user or outside of CI/CD workflows, it may indicate a compromise.

Possible Investigation Steps

  • Identify the Source User: Check aws.cloudtrail.user_identity.arn, access key ID, and session type (IAMUser, AssumedRole, etc).
  • Review File Content: Use the S3 GetObject or CloudTrail requestParameters to inspect the uploaded file for signs of obfuscation or injection.
  • Correlate to Other Events: Review events from the same IAM user before and after the upload (e.g., ListBuckets, GetCallerIdentity, IAM activity).
  • Look for Multiple Uploads: Attackers may attempt to upload several files or modify multiple directories.

False Positive Analysis

  • This behavior may be expected during app deployments. Look at:
    • The user_agent.original to detect legitimate CI tools (like Terraform or GitHub Actions).
    • Timing patterns—does this match a regular release window?
    • The origin IP and device identity.

Response and Remediation

  • Revert Malicious Code: Replace the uploaded JS file with a clean version and invalidate CloudFront cache if applicable.
  • Revoke Access: If compromise is confirmed, revoke the IAM credentials and disable the user.
  • Audit IAM Policies: Ensure that only deployment users can modify static site buckets.
  • Enable Bucket Versioning: This can allow for quick rollback and historical review.

References

Related rules

to-top