Detection rules › Sigma
Loaded LiquidJS error page template contains XSS vulnerabilities
This detection monitors if there are patterns that indicate potential Cross-Site Scripting (XSS) vulnerabilities in a LiquidJS error page template.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Stealth | T1562.007 Impair Defenses: Disable or Modify Cloud Firewall |
Rule body yaml
title: Loaded LiquidJS error page template contains XSS vulnerabilities
description: |
This detection monitors if there are patterns that indicate potential Cross-Site Scripting (XSS)
vulnerabilities in a LiquidJS error page template.
id: 8281291e-51b4-46a9-8012-955e20206efd
status: experimental
author: Okta
date: 2025-07-11
modified: 2025-08-04
logsource:
product: auth0
detection:
selection:
data.type: sapi
data.description: "Update tenant settings"
vulnerable_variables:
# This regex matches LiquidJS variables that are unfiltered
data.details.response.body.error_page.html|re: '\{\{([^}]+?)(?:\s*\|\s*(?!escape|escape_once|h|html_escape)[^}]+)??\s*\}\}|\{\{([^}|]+)\}\}'
condition: selection and vulnerable_variables
explanation: >
The query searches for events where tenant settings have been modified.
To examine an error page the 'data.details.response.body.error_page.html' path of the json object needs to be reviewed.
The Splunk query looks for a XSS vulnerability introduced by unescaped variables - {{ variable }} - by applying a regex.
It also outputs the whole error_page template, list of filters, list of vulnerable filters, and modifying IP.
splunk: |
index=auth0 data.tenant_name="{your-tenant-name}"
data.type=sapi data.description="Update tenant settings"
| fields data.details.response.body.error_page.html, data.ip
| spath path=data.details.response.body.error_page.html output=error_page_html
| rex field=error_page_html "{{(?<variable_with_filter>[^}]+?)}}" max_match=0
| eval safe_variables = mvfind(variable_with_filter, "\|\s*(escape|escape_once|h|html_escape)")
| eval vulnerable_variables = mvfilter(NOT match(variable_with_filter, "\|\s*(escape|escape_once|h|html_escape)"))
| where isnotnull(vulnerable_variables)
| table _time, data.ip, error_page_html, variable_with_filter, vulnerable_variables
comments:
- The Splunk query above shall be tuned to reflect a valid tenant name.
- The Sigma query converted into the Splunk backend returns only those records where all variables are vulnerable.
- Thus, it misses the cases where only some variables are vulnerable. The provided Splunk query addresses this gap.
tenant_logs: |
type:"sapi" AND description: "Update tenant settings"
prevention:
- Apply known linters, e.g. shopify (maintainer of liquidjs) has some linters we can reference
https://github.com/Shopify/theme-tools/tree/main/packages/theme-check-common.
false_positive: |
- Parameters that do not have escape filters but are not vulnerable to XSS,
such as using the date filter '{{ "now" | date: "%Y-%m-%d %H:%M" }}'
tags:
- attack.defense-evasion
- attack.t1562
- attack.t1562.007
Stages and Predicates
Stage 0: condition
selection and vulnerable_variablesStage 1: selection
selection:
data.type: sapi
data.description: "Update tenant settings"
Stage 2: vulnerable_variables
vulnerable_variables:
data.details.response.body.error_page.html|re: '\{\{([^}]+?)(?:\s*\|\s*(?!escape|escape_once|h|html_escape)[^}]+)??\s*\}\}|\{\{([^}|]+)\}\}'
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.
| Field | Kind | Values |
|---|---|---|
data.description | eq |
|
data.details.response.body.error_page.html | regex_match |
|
data.type | eq |
|