diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..6fe95cf
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,29 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**Powerpipe version (`powerpipe -v`)**
+Example: v0.3.0
+
+**Tailpipe version (`tailpipe -v`)**
+Example: v0.3.0
+
+**Plugin version (`tailpipe plugin list`)**
+Example: v0.5.0
+
+**To reproduce**
+Steps to reproduce the behavior (please include relevant code and/or commands).
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..d645812
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,11 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Questions
+ url: https://turbot.com/community/join
+ about: GitHub issues in this repository are only intended for bug reports and feature requests. Other issues will be closed. Please ask and answer questions through the Turbot Slack community.
+ - name: Powerpipe CLI Bug Reports and Feature Requests
+ url: https://github.com/turbot/powerpipe/issues/new/choose
+ about: Powerpipe CLI has its own codebase. Bug reports and feature requests for those pieces of functionality should be directed to that repository.
+ - name: Tailpipe CLI Bug Reports and Feature Requests
+ url: https://github.com/turbot/tailpipe/issues/new/choose
+ about: Tailpipe CLI has its own codebase. Bug reports and feature requests for those pieces of functionality should be directed to that repository.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..11fc491
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..e89850e
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,2 @@
+### Checklist
+- [ ] Issue(s) linked
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 0000000..64fd28d
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,17 @@
+name: Stale Issues and PRs
+on:
+ schedule:
+ - cron: "30 23 * * *"
+ workflow_dispatch:
+ inputs:
+ dryRun:
+ description: Set to true for a dry run
+ required: false
+ default: "false"
+ type: string
+
+jobs:
+ stale_workflow:
+ uses: turbot/steampipe-workflows/.github/workflows/stale.yml@main
+ with:
+ dryRun: ${{ github.event.inputs.dryRun }}
\ No newline at end of file
diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml
new file mode 100644
index 0000000..c5200fb
--- /dev/null
+++ b/.github/workflows/sync-labels.yml
@@ -0,0 +1,9 @@
+name: Sync Labels
+on:
+ schedule:
+ - cron: "30 22 * * 1"
+ workflow_dispatch:
+
+jobs:
+ sync_labels_workflow:
+ uses: turbot/steampipe-workflows/.github/workflows/sync-labels.yml@main
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..50e1233
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,11 @@
+## v0.1.0 [2025-04-16]
+
+ _What's new?_
+
+ - New benchmarks added:
+ - MITRE ATT&CK v16.1 benchmark (`powerpipe benchmark run nginx_access_log_detections.benchmark.mitre_attack_v161`).
+ - Nginx Access Log Detections benchmark (`powerpipe benchmark run nginx_access_log_detections.benchmark.access_log_detections`).
+ - OWASP Top 10 2021 benchmark (`powerpipe benchmark run nginx_access_log_detections.benchmark.owasp_top_10_2021`).
+
+ - New dashboards added:
+ - [Nginx Access Log Activity Dashboard](https://hub.powerpipe.io/mods/turbot/tailpipe-mod-nginx-access-log-detections/dashboards/dashboard.activity_dashboard)
\ No newline at end of file
diff --git a/README.md b/README.md
index 3fe0718..a61d178 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,14 @@
# Nginx Access Log Detections Mod for Powerpipe
-View dashboards, run detections and scan for anomalies across your Nginx access logs.
+[Tailpipe](https://tailpipe.io) is an open-source CLI tool that allows you to collect logs and query them with SQL.
-
+The [Nginx Access Log Detections Mod](https://hub.powerpipe.io/mods/turbot/tailpipe-mod-nginx-access-log-detections) contains pre-built dashboards and detections, which can be used to monitor and analyze activity across your Nginx servers.
+
+Run detection benchmarks:
+
+
+View insights in dashboards:
+
## Documentation
@@ -102,13 +106,12 @@ List available benchmarks:
powerpipe benchmark list
```
-
+
Different output formats are also available, for more information please see
[Output Formats](https://powerpipe.io/docs/reference/cli/benchmark#output-formats).
@@ -126,4 +129,4 @@ Want to help but don't know where to start? Pick up one of the `help wanted` iss
- [Powerpipe](https://github.com/turbot/powerpipe/labels/help%20wanted)
- [Tailpipe](https://github.com/turbot/tailpipe/labels/help%20wanted)
-- [Nginx Access Log Detections Mod](https://github.com/turbot/tailpipe-mod-nginx0-access-log-detections/labels/help%20wanted)
\ No newline at end of file
+- [Nginx Access Log Detections Mod](https://github.com/turbot/tailpipe-mod-nginx-access-log-detections/labels/help%20wanted)
diff --git a/dashboards/activity_dashboard.pp b/dashboards/activity_dashboard.pp
new file mode 100644
index 0000000..978a083
--- /dev/null
+++ b/dashboards/activity_dashboard.pp
@@ -0,0 +1,337 @@
+dashboard "activity_dashboard" {
+ title = "Access Log Activity Dashboard"
+ documentation = file("./dashboards/docs/activity_dashboard.md")
+
+ tags = {
+ type = "Dashboard"
+ service = "Nginx/AccessLog"
+ }
+
+ container {
+ # Analysis
+ card {
+ query = query.activity_dashboard_total_logs
+ width = 2
+ }
+
+ card {
+ query = query.activity_dashboard_success_count
+ width = 2
+ type = "ok"
+ }
+
+ card {
+ query = query.activity_dashboard_redirect_count
+ width = 2
+ type = "info"
+ }
+
+ card {
+ query = query.activity_dashboard_bad_request_count
+ width = 2
+ type = "alert"
+ }
+
+ card {
+ query = query.activity_dashboard_error_count
+ width = 2
+ type = "alert"
+ }
+ }
+
+ container {
+ chart {
+ title = "Requests by Day"
+ query = query.activity_dashboard_requests_by_day
+ width = 6
+ type = "line"
+ }
+
+ chart {
+ title = "Requests by HTTP Method"
+ query = query.activity_dashboard_requests_by_http_method
+ width = 6
+ type = "bar"
+ }
+
+ chart {
+ title = "Requests by Status Code"
+ query = query.activity_dashboard_requests_by_status_code
+ width = 6
+ type = "pie"
+ }
+
+ chart {
+ title = "Top 10 User Agents (Requests)"
+ query = query.activity_dashboard_requests_by_user_agent
+ width = 6
+ type = "pie"
+ }
+
+ chart {
+ title = "Top 10 Clients (Requests)"
+ query = query.activity_dashboard_top_10_clients
+ width = 6
+ type = "table"
+ }
+
+ chart {
+ title = "Top 10 URLs (Requests)"
+ query = query.activity_dashboard_top_10_urls
+ width = 6
+ type = "table"
+ }
+
+ chart {
+ title = "Top 10 URLs (Successful Requests)"
+ query = query.activity_dashboard_requests_by_successful_requests
+ width = 6
+ type = "table"
+ }
+
+ chart {
+ title = "Top 10 URLs (Errors)"
+ query = query.activity_dashboard_requests_by_errors
+ width = 6
+ type = "table"
+ }
+ }
+}
+
+# Queries
+query "activity_dashboard_total_logs" {
+ title = "Log Count"
+ description = "Count the total Nginx log entries."
+
+ sql = <<-EOQ
+ select
+ count(*) as "Total Requests"
+ from
+ nginx_access_log;
+ EOQ
+}
+
+query "activity_dashboard_success_count" {
+ title = "Successful Request Count"
+ description = "Count of successful HTTP requests (status 2xx)."
+
+ sql = <<-EOQ
+ select
+ count(*) as "Successful (2xx)"
+ from
+ nginx_access_log
+ where
+ status between 200 and 299;
+ EOQ
+}
+
+query "activity_dashboard_redirect_count" {
+ title = "Redirect Request Count"
+ description = "Count of redirect HTTP requests (status 3xx)."
+
+ sql = <<-EOQ
+ select
+ count(*) as "Redirections (3xx)"
+ from
+ nginx_access_log
+ where
+ status between 300 and 399;
+ EOQ
+}
+
+query "activity_dashboard_bad_request_count" {
+ title = "Bad Request Count"
+ description = "Count of client error HTTP requests (status 4xx)."
+
+ sql = <<-EOQ
+ select
+ count(*) as "Bad Requests (4xx)"
+ from
+ nginx_access_log
+ where
+ status between 400 and 499;
+ EOQ
+}
+
+query "activity_dashboard_error_count" {
+ title = "Server Error Count"
+ description = "Count of server error HTTP requests (status 5xx)."
+
+ sql = <<-EOQ
+ select
+ count(*) as "Server Errors (5xx)"
+ from
+ nginx_access_log
+ where
+ status between 500 and 599;
+ EOQ
+}
+
+query "activity_dashboard_top_10_clients" {
+ title = "Top 10 Clients (Requests)"
+ description = "List the top 10 client IPs by request count."
+
+ sql = <<-EOQ
+ select
+ remote_addr as "Client IP",
+ count(*) as "Request Count"
+ from
+ nginx_access_log
+ group by
+ remote_addr
+ order by
+ count(*) desc,
+ remote_addr
+ limit 10;
+ EOQ
+}
+
+query "activity_dashboard_top_10_urls" {
+ title = "Top 10 URLs (Requests)"
+ description = "List the top 10 requested URLs by request count."
+
+ sql = <<-EOQ
+ select
+ request_uri as "URL",
+ count(*) as "Request Count"
+ from
+ nginx_access_log
+ where
+ request_uri is not null
+ group by
+ request_uri
+ order by
+ count(*) desc,
+ request_uri
+ limit 10;
+ EOQ
+}
+
+query "activity_dashboard_requests_by_day" {
+ title = "Requests by Day"
+ description = "Count of requests grouped by day."
+
+ sql = <<-EOQ
+ select
+ strftime(tp_timestamp, '%Y-%m-%d') as "Date",
+ count(*) as "Request Count"
+ from
+ nginx_access_log
+ group by
+ strftime(tp_timestamp, '%Y-%m-%d')
+ order by
+ strftime(tp_timestamp, '%Y-%m-%d');
+ EOQ
+}
+
+query "activity_dashboard_requests_by_status_code" {
+ title = "Requests by Status Code"
+ description = "Count of rqeuests grouped by status code."
+
+ sql = <<-EOQ
+ select
+ case
+ when status between 200 and 299 then '2xx Success'
+ when status between 300 and 399 then '3xx Redirect'
+ when status between 400 and 499 then '4xx Client Error'
+ when status between 500 and 599 then '5xx Server Error'
+ else 'Other'
+ end as "Status Category",
+ count(*) as "Request Count"
+ from
+ nginx_access_log
+ where
+ status is not null
+ group by
+ "Status Category"
+ order by
+ "Status Category";
+ EOQ
+}
+
+query "activity_dashboard_requests_by_http_method" {
+ title = "Requests by HTTP Method"
+ description = "Distribution of HTTP methods used in requests."
+
+ sql = <<-EOQ
+ select
+ request_method as "HTTP Method",
+ count(*) as "Request Count"
+ from
+ nginx_access_log
+ where
+ request_method is not null
+ group by
+ request_method
+ order by
+ count(*) asc,
+ request_method;
+ EOQ
+}
+
+query "activity_dashboard_requests_by_successful_requests" {
+ title = "Top 10 URLs (Successful Requests)"
+ description = "List the top 10 requested URLs by successful request count."
+
+ sql = <<-EOQ
+ select
+ request_uri as "Path",
+ count(*) as "Request Count",
+ string_agg(distinct status::text, ', ' order by status::text) as "Status Codes"
+ from
+ nginx_access_log
+ where
+ status between 200 and 299
+ and request_uri is not null
+ group by
+ request_uri
+ order by
+ count(*) desc,
+ request_uri
+ limit 10;
+ EOQ
+}
+
+query "activity_dashboard_requests_by_errors" {
+ title = "Top 10 URLs (Errors)"
+ description = "List the top 10 requested URLs by error count."
+
+ sql = <<-EOQ
+ select
+ request_uri as "Path",
+ count(*) as "Error Count",
+ string_agg(distinct status::text, ', ' order by status::text) as "Status Codes"
+ from
+ nginx_access_log
+ where
+ status between 400 and 599
+ and request_uri is not null
+ group by
+ request_uri
+ order by
+ count(*) desc,
+ request_uri
+ limit 10;
+ EOQ
+}
+
+query "activity_dashboard_requests_by_user_agent" {
+ title = "Top 10 User Agents (Requests)"
+ description = "Distribution of user agents in requests."
+
+ sql = <<-EOQ
+ select
+ http_user_agent as "User Agent",
+ count(*) as "Request Count"
+ from
+ nginx_access_log
+ where
+ http_user_agent is not null
+ group by
+ http_user_agent
+ order by
+ count(*) desc,
+ http_user_agent
+ limit 10;
+ EOQ
+}
diff --git a/dashboards/docs/activity_dashboard.md b/dashboards/docs/activity_dashboard.md
new file mode 100644
index 0000000..affec40
--- /dev/null
+++ b/dashboards/docs/activity_dashboard.md
@@ -0,0 +1,12 @@
+This dashboard answers the following questions:
+
+- How many HTTP requests has the Nginx server handled?
+- What is the distribution of HTTP status codes (success, redirect, client errors, server errors)?
+- What HTTP methods are being used most frequently?
+- How has request volume and data transfer changed over time?
+- Which browsers and tools are accessing the server?
+- Which client IPs are generating the most traffic?
+- Which URIs are most frequently requested?
+- Which endpoints have the slowest response times?
+- Which paths are generating the most client errors?
+- What is the total data volume being transferred through the Nginx server?
diff --git a/detections/access_logs.pp b/detections/access_logs.pp
new file mode 100644
index 0000000..d37a919
--- /dev/null
+++ b/detections/access_logs.pp
@@ -0,0 +1,15 @@
+benchmark "access_log_detections" {
+ title = "Access Log Detections"
+ description = "This benchmark contains recommendations when scanning Nginx access logs."
+ type = "detection"
+ children = [
+ benchmark.cross_site_scripting_detections,
+ benchmark.local_file_inclusion_detections,
+ benchmark.remote_command_execution_detections,
+ benchmark.sql_injection_detections,
+ ]
+
+ tags = merge(local.nginx_access_log_detections_common_tags, {
+ type = "Benchmark"
+ })
+}
\ No newline at end of file
diff --git a/detections/cross_site_scripting.pp b/detections/cross_site_scripting.pp
new file mode 100644
index 0000000..3f25302
--- /dev/null
+++ b/detections/cross_site_scripting.pp
@@ -0,0 +1,576 @@
+locals {
+ cross_site_scripting_common_tags = merge(local.nginx_access_log_detections_common_tags, {
+ category = "Cross-Site Scripting"
+ })
+}
+
+benchmark "cross_site_scripting_detections" {
+ title = "Cross-Site Scripting (XSS) Detections"
+ description = "This benchmark contains cross-site scripting (XSS) focused detections when scanning access logs."
+ type = "detection"
+ children = [
+ detection.cross_site_scripting_angular_template,
+ detection.cross_site_scripting_attribute_injection,
+ detection.cross_site_scripting_common_patterns,
+ detection.cross_site_scripting_dom_based,
+ detection.cross_site_scripting_encoding,
+ detection.cross_site_scripting_html_injection,
+ detection.cross_site_scripting_javascript_methods,
+ detection.cross_site_scripting_javascript_uri,
+ detection.cross_site_scripting_script_tag,
+ ]
+
+ tags = merge(local.cross_site_scripting_common_tags, {
+ type = "Benchmark"
+ })
+}
+
+detection "cross_site_scripting_angular_template" {
+ title = "Cross-Site Scripting AngularJS Template"
+ description = "Detect potential AngularJS template injection attacks that can lead to Cross-Site Scripting in requests and User-Agent headers."
+ documentation = file("./detections/docs/cross_site_scripting_angular_template.md")
+ severity = "high"
+ display_columns = local.detection_display_columns
+
+ query = query.cross_site_scripting_angular_template
+
+ tags = merge(local.cross_site_scripting_common_tags, {
+ mitre_attack_ids = "TA0002:T1059.007",
+ owasp_top_10 = "A03:2021-Injection"
+ })
+}
+
+query "cross_site_scripting_angular_template" {
+ sql = <<-EOQ
+ select
+ ${local.detection_sql_columns}
+ from
+ nginx_access_log
+ where
+ (
+ request_uri is not null
+ and (
+ -- Common AngularJS injection patterns
+ request_uri ilike '%constructor.constructor%'
+ or request_uri ilike '%$eval%'
+ or request_uri ilike '%ng-init%'
+ or request_uri ilike '%ng-bind%'
+ or request_uri ilike '%ng-include%'
+ )
+ )
+ OR
+ (
+ http_user_agent is not null
+ and (
+ -- Common AngularJS injection patterns
+ http_user_agent ilike '%constructor.constructor%'
+ or http_user_agent ilike '%$eval%'
+ or http_user_agent ilike '%ng-init%'
+ or http_user_agent ilike '%ng-bind%'
+ or http_user_agent ilike '%ng-include%'
+ )
+ )
+ order by
+ tp_timestamp desc;
+ EOQ
+}
+
+detection "cross_site_scripting_attribute_injection" {
+ title = "Cross-Site Scripting Attribute Injection"
+ description = "Detect Cross-Site Scripting attacks using HTML attribute injection, such as event handlers or dangerous attributes in requests and User-Agent headers."
+ documentation = file("./detections/docs/cross_site_scripting_attribute_injection.md")
+ severity = "high"
+ display_columns = local.detection_display_columns
+
+ query = query.cross_site_scripting_attribute_injection
+
+ tags = merge(local.cross_site_scripting_common_tags, {
+ mitre_attack_ids = "TA0002:T1059.007",
+ owasp_top_10 = "A03:2021-Injection"
+ })
+}
+
+query "cross_site_scripting_attribute_injection" {
+ sql = <<-EOQ
+ select
+ ${local.detection_sql_columns}
+ from
+ nginx_access_log
+ where
+ (
+ request_uri is not null
+ and (
+ -- Attribute injection patterns
+ request_uri ilike '%onerror=%'
+ or request_uri ilike '%onload=%'
+ or request_uri ilike '%onmouseover=%'
+ or request_uri ilike '%onmouseout=%'
+ or request_uri ilike '%onclick=%'
+ or request_uri ilike '%onfocus=%'
+ or request_uri ilike '%onblur=%'
+ or request_uri ilike '%onchange=%'
+ or request_uri ilike '%onsubmit=%'
+ or request_uri ilike '%onkeypress=%'
+ -- Less common event handlers
+ or request_uri ilike '%onreadystatechange=%'
+ or request_uri ilike '%onbeforeonload=%'
+ or request_uri ilike '%onanimationstart=%'
+ -- Dangerous attributes
+ or request_uri ilike '%formaction=%'
+ or request_uri ilike '%xlink:href=%'
+ or request_uri ilike '%data:text/html%'
+ or request_uri ilike '%pattern=%'
+ )
+ )
+ OR
+ (
+ http_user_agent is not null
+ and (
+ -- Attribute injection patterns
+ http_user_agent ilike '%onerror=%'
+ or http_user_agent ilike '%onload=%'
+ or http_user_agent ilike '%onmouseover=%'
+ or http_user_agent ilike '%onmouseout=%'
+ or http_user_agent ilike '%onclick=%'
+ or http_user_agent ilike '%onfocus=%'
+ or http_user_agent ilike '%onblur=%'
+ or http_user_agent ilike '%onchange=%'
+ or http_user_agent ilike '%onsubmit=%'
+ or http_user_agent ilike '%onkeypress=%'
+ -- Less common event handlers
+ or http_user_agent ilike '%onreadystatechange=%'
+ or http_user_agent ilike '%onbeforeonload=%'
+ or http_user_agent ilike '%onanimationstart=%'
+ -- Dangerous attributes
+ or http_user_agent ilike '%formaction=%'
+ or http_user_agent ilike '%xlink:href=%'
+ or http_user_agent ilike '%data:text/html%'
+ or http_user_agent ilike '%pattern=%'
+ )
+ )
+ order by
+ tp_timestamp desc;
+ EOQ
+}
+
+detection "cross_site_scripting_encoding" {
+ title = "Cross-Site Scripting Encoding"
+ description = "Detect Cross-Site Scripting attacks using various encoding techniques to bypass filters in requests and User-Agent headers."
+ documentation = file("./detections/docs/cross_site_scripting_encoding.md")
+ severity = "high"
+ display_columns = local.detection_display_columns
+
+ query = query.cross_site_scripting_encoding
+
+ tags = merge(local.cross_site_scripting_common_tags, {
+ mitre_attack_ids = "TA0002:T1059.007",
+ owasp_top_10 = "A03:2021-Injection"
+ })
+}
+
+query "cross_site_scripting_encoding" {
+ sql = <<-EOQ
+ select
+ ${local.detection_sql_columns}
+ from
+ nginx_access_log
+ where
+ (
+ request_uri is not null
+ and (
+ -- HTML entity encoding
+ request_uri ilike '%<script%' -- Hex entity encoded
+ or http_user_agent ilike '%<img%onerror%' -- Hex encoded
` when rendered by the browser. Similarly, Base64 encoding can be used to completely obscure the contents of a payload until it's decoded and executed.
+
+By examining both request URIs and User-Agent headers, this detection can identify attackers who attempt to evade security controls by hiding their encoded payloads in HTTP headers rather than request parameters. This comprehensive approach helps security teams identify sophisticated XSS attempts that specifically aim to bypass traditional security controls through encoding techniques.
+
+**References**:
+- [OWASP XSS Filter Evasion Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html)
+- [CWE-79: Improper Neutralization of Input During Web Page Generation](https://cwe.mitre.org/data/definitions/79.html)
+- [OWASP Top 10 2021: A03 Injection](https://owasp.org/Top10/A03_2021-Injection/)
+- [MITRE ATT&CK: T1059.007 Command and Scripting Interpreter: JavaScript](https://attack.mitre.org/techniques/T1059/007/)
\ No newline at end of file
diff --git a/detections/docs/cross_site_scripting_event_handlers.md b/detections/docs/cross_site_scripting_event_handlers.md
new file mode 100644
index 0000000..7608716
--- /dev/null
+++ b/detections/docs/cross_site_scripting_event_handlers.md
@@ -0,0 +1,17 @@
+## Overview
+
+The XSS Event Handler Attack detection identifies Cross-Site Scripting (XSS) attacks that specifically target HTML event handlers to execute malicious JavaScript. Event handlers like `onload`, `onerror`, and `onclick` can be injected into HTML elements to trigger JavaScript execution when certain browser events occur.
+
+This detection examines both HTTP requests and User-Agent headers for patterns indicating event handler-based XSS attempts. It focuses on identifying both common event handlers that are frequently targeted in XSS attacks and less common event handlers that may be used to evade basic security filters.
+
+Event handler XSS attacks are particularly dangerous because they can bypass traditional XSS filters that focus primarily on script tags. Attackers can inject these event handlers into various HTML elements, creating multiple attack vectors. For example, an attacker might inject `
` into a comment field, causing the malicious JavaScript to execute when the image fails to load.
+
+Modern web applications have numerous event handlers available, and new ones are introduced with each HTML5 specification update. This detection looks for patterns indicating attempts to exploit these event handlers in both request URIs and User-Agent headers, allowing it to catch attackers who attempt to evade detection by hiding their payloads in HTTP headers rather than request parameters.
+
+By monitoring for these event handler patterns, security teams can identify both reconnaissance activities and active exploitation attempts targeting their web applications through this specific XSS vector.
+
+**References**:
+- [OWASP XSS Filter Evasion Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html)
+- [CWE-79: Improper Neutralization of Input During Web Page Generation](https://cwe.mitre.org/data/definitions/79.html)
+- [OWASP Top 10 2021: A03 Injection](https://owasp.org/Top10/A03_2021-Injection/)
+- [MITRE ATT&CK: T1059.007 Command and Scripting Interpreter: JavaScript](https://attack.mitre.org/techniques/T1059/007/)
\ No newline at end of file
diff --git a/detections/docs/cross_site_scripting_html_injection.md b/detections/docs/cross_site_scripting_html_injection.md
new file mode 100644
index 0000000..26520ea
--- /dev/null
+++ b/detections/docs/cross_site_scripting_html_injection.md
@@ -0,0 +1,17 @@
+## Overview
+
+The XSS HTML Injection detection identifies Cross-Site Scripting (XSS) attacks that use HTML tag injection to execute malicious JavaScript. Unlike direct script tag injection, this attack vector leverages various HTML elements with event handlers or specific attributes that can execute JavaScript code.
+
+This detection examines both HTTP requests and User-Agent headers for HTML elements commonly used in XSS attacks, including `