Skip to main content
Version: 1.2.1-beta.1

AST Engine

The AST engine is responsible for parsing the steps of a rule with type ast. Following is an example of what the headers of a rule would look like:

id: <id>
name: <human_readable_name>
author: <author>
description: <description>
severity: <info | low | medium | high>
type: ast
tech:
- <tech>

steps:
- name: <name_of_the_step>
message: <message>
requires:
- <previous_step_name>
...

AST Step

An AST step is used to match the specific parts of an AST (Abstract Syntax Tree) in a JS file.

ESQuery

ESQuery is a query language for JavaScript ASTs. It is used to match the specific parts in a JavaScript file.

For comparison, consider the following HTML tree:

<html>
<body>
<div>
<form></form>
</div>
</body>
</html>

If you had to get the <form> element inside a <div>, which is then nested inside the <body> element with <html> as parent, you would use the following XPath query:

/html/body/div/form

ESQuery works in a similar way. Let's say want to match the following JS snippet:

window.addEventListener("message", e);

If you know what the above snippet does, you would know that it is one of the first thing that you would do when searching for post-message vulnerabilities. To match it, you would use the following ESQuery query:

CallExpression[callee.object.name="window"][callee.property.name="addEventListener"][arguments.0.value="message"][arguments.1]

Now that you are familiar with what an ESQuery is, let's see how to use it in a rule file:

- name: <name>
message: <message>
esquery:
type: esquery
query: <query>

The return type for this step is Node.

For example, a rule to detect post-message listeners would look like this:

Example: Full rule file for checking if the "Authorization" header is present in the request
id: detect_postMessage
name: Detect postMessage event listeners
author: shriyanss
description: Detect postMessage event listeners
severity: info
type: ast
tech:
- next

steps:
- name: check_postMessage
message: postMessage event listener detected
esquery:
type: esquery
query: CallExpression[callee.object.name="window"][callee.property.name="addEventListener"][arguments.0.value="message"][arguments.1]

Unfortunately, there is no official documentation for ESQuery. However, you can use ASTExplorer to test build your ESQuery queries.

Some of the common ESQuery examples are:
  • Identifier[name="fetch"]
fetch;
  • CallExpression[callee.name="fetch"]
fetch();
  • MemberExpression[property.name="innerHTML"]
something.innerHTML;
  • VariableDeclarator[id.name="token"]
let token = "value";
  • AssignmentExpression[left.property.name="innerHTML"]
something.innerHTML = "value";
  • ImportDeclaration[source.value="axios"]
import axios from "axios";
  • CallExpression[callee.name="setTimeout"][arguments.length=2]
setTimeout(() => {}, 1000);
  • NewExpression[callee.name="XMLHttpRequest"]
new XMLHttpRequest();

Post Message Function Resolve

You can use this to resolve a function that is called when the postMessage event is triggered. For this, you would first need a valid ESQuery query to match the postMessage event listener.

To use this step, you can use the following:

- name: <name>
message: <message>
postMessageFunctionResolve:
name: <postMessage_step_name>

The return type for this step is Node.

For example, a rule to resolve the code for the function that is called when the postMessage event is triggered would look like this:

Example: Full rule file to get the code for the function that is called when the postMessage event is triggered
id: detect_postMessage_function
name: postMessage event listeners function code
author: shriyanss
description: Detect postMessage event listeners function code
severity: info
type: ast
tech:
- next

steps:
- name: check_postMessage
message: postMessage event listener detected
esquery:
type: esquery
query: CallExpression[callee.object.name="window"][callee.property.name="addEventListener"][arguments.0.value="message"][arguments.1]
# now, check if the second argument is a function and it has call to innerHtml
- name: resolve_event_handler_function
message: Code for postmessage event handler
requires:
- check_postMessage
postMessageFuncResolve:
name: check_postMessage

Check Assignment Exist

You can use this to find if a variable is assigned to something. For this, you would need a step whose return type is Node.

To use this step, you can use the following:

- name: <name>
message: <message>
checkAssignmentExist:
name: <node_step_name>
type: <var_name_to_check_assignment_for>
memberExpression: <boolean>

For example, to check if a innerHTML is being assigned a value in a node which is the function code for a postMessage event listener, you can use the following:

Example: Full rule file to check if a innerHTML is being assigned a value in a node which is the function code for a postMessage event listener
id: detect_postMessage_innerHtml_sink
name: postMessage event listeners with innerHTML
author: shriyanss
description: Detect postMessage event listeners with innerHTML sink
severity: medium
type: ast
tech:
- next

steps:
- name: check_postMessage
message: postMessage event listener detected
esquery:
type: esquery
query: CallExpression[callee.object.name="window"][callee.property.name="addEventListener"][arguments.0.value="message"][arguments.1]
# now, check if the second argument is a function and it has call to innerHtml
- name: resolve_event_handler_function
message: Code for postmessage event handler
requires:
- check_postMessage
postMessageFuncResolve:
name: check_postMessage
- name: check_innerHtml
message: Check if innerHTML is being assigned something
requires:
- resolve_event_handler_function
checkAssignmentExist:
name: resolve_event_handler_function
type: innerHTML
memberExpression: true