Skip to main content

Custom Engine Rules

Overview

This section explains the process of how to add your own custom engine rules for specific languages in order to use it as a part of your scans.

At the moment, you can add your own custom rules for the amazing Semgrep tool. We are planning to support a range of other tools and allow you to plugin your own rules and patterns, which will be instantly available to scan every new line of code across all your repositories.

Table of Contents

Semgrep

To get started with leveraging your own rules for Semgrep, there are three steps to follow:

Step 1

Head over to the Semgrep playground and select the language to write the rule for. We are going to use Javascript for the example. Then select the "Advanced Tab" which allows you to write YAML directly. You could use the "Simple Tab" first and when you get ready for step 2, just switch to the "Advanced tab" to get the generated rule code.

Let's take a look at our simple example rule code:

rules:
- id: custom-guardrails-test-rule
patterns:
- pattern: |
$LIB.dangerousFunction(...)
- pattern-not: |
$LIB.dangerousFunction("...")
message: The dangerousFunction is called.
severity: ERROR
languages: [javascript, typescript]
metadata:
grId: GR0002
grTitle: Use of dangerousFunction()
grDocs: https://docs.example.com/dont-use-dangerous-function
grSeverity: high

The rules: object is required to make it a proper Semgrep rule file. The rules objects have an array of id objects that are used to uniquely identify a rule. Each rule must have either one of these pattern, patterns, pattern-either, or pattern-regex. In our case we are using patterns, which can have an array of pattern elements. Message is another required element that can provide more details about what this rule identifies. The last two required elements are severity which could be either INFO, WARNING, or ERROR and languages. A list of supported languages can be found here.

In addition to properties required by Semgrep, GuardRails supports 4 properties in the metadata object. This is required to help GuardRails understand how to map and process these rules.

The first element, grId, is the only required element. It must have one of these GRXXXX values:

  • GR0001: Insecure Use of SQL Queries
  • GR0002: Insecure Use of Dangerous Function
  • GR0003: Insecure Use of Regular Expressions
  • GR0004: Hard-Coded Secrets
  • GR0005: Insecure Authentication
  • GR0006: Insecure Access Control
  • GR0007: Insecure Configuration
  • GR0008: Insecure File Management
  • GR0009: Insecure Use of Crypto
  • GR0010: Insecure Use of Language/Framework API
  • GR0011: Insecure Processing of Data
  • GR0012: Insecure Network Communication
  • GR0013: Using Vulnerable Libraries
  • GR0014: Privacy Concerns
  • GR0015: Information Disclosure

Additional metadata properties are:

  • grTitle will determine what is shown when the issue is being flagged in a PR/MR or shown in the dashboard.
  • grDocs will point to any documentation link, even to your intranet and will allow developers to see how to fix a flagged issue.
  • grSeverity will show the severity in the UI. Possible values are low, medium, high, or critical.

As the next step, you should create some test code to make sure that the rule is working as expected. The example test code is shown below:

console.log("calling dangerousFunction() with static string");
var userInput = req.body.danger;
lib.dangerousFunction("static input is fine"); // compliant
console.log("calling dangerousFunction() with user input");
lib.dangerousFunction(userInput); // non-compliant
console.log("dangerousFunction() called successfully");

A screenshot of a successful execution looks on semgrep.dev is shown below:

Semgrep playground

More up-to-date information on how to write Semgrep rules can be found here.

Step 2

Now that we have tested our rules in the Semgrep playground, it is time to add them to the GuardRails dashboard. Login to the dashboard first and then browse to Settings->Custom Engine Rules and select the language you want to add the rules for. In our case Javascript.

This will look like this:

GR Dashboard Config

You can copy the rules yaml text into the textarea and press save.

Save Custom Rules

Note that you can also configure the engine behavior. For example, you can prevent your custom rules from running, or you can ignore the core rules that we have created and shipped with each Semgrep-specific engine from running. If your own rules are too noisy, you can quickly disable them, without having to delete the textarea, or if you just want to run your own rules, then you can disable the GuardRails rules from running.

Step 3

The final step is to test that everything is working as expected and the results of the new rules show up. To do that just go to any Javascript repo that you have and create a new PR/MR with the test code that we used to test the rule in step 1.

As an example we show a PR in the GitHub UI that identifies that issue:

PR Finding

And also how this looks in the GuardRails dashboard:

Dashboard Finding

That's it, from this moment onwards every use of dangerousFunction() would be flagged across your entire portfolio. No need to directly tinker with any tools, CI/CD pipelines, etc. It just works :)