Pattern

AST とシンボリックな照合

any/all

フィールド説明
any条件のうち一つ以上を満たせば一致
all列挙した条件すべてを満たす場合に一致

例 1: method_1 または method_2 の呼び出しを探します。

yaml
any:
  - pattern: method_1($$$)
  - pattern: method_2($$$)

例 2:

yaml
all:
  - pattern: method_1($$$)
  - inside:
      pattern: $F(async ($REQ, $RES) => {$$$})
  - inside:
      pattern: for($IN = $S; $$$; $$$) {$$$}

not

特定のパターンを除外する場合に not を使います。

yaml
pattern: $REQ.META
not:
  inside:
    any:
      - pattern: $REQ.META.CONTENT_LENGTH
      - pattern: $REQ.META.CONTENT_TYPE

regex

正規表現による照合を行います。

例: メタ変数 STR に格納した文字列を正規表現で調べ、polyfill.io の URL を探します。

yaml
pattern: |
  "$STR"
metavar:
  name: STR
  eq:
    regex: '(?:https?:)?//(?:[^/]*\.)?polyfill\.io'

以下のコードが一致します。

javascript
async function loadPolyfill() {
  await import("https://polyfill.io/v3/polyfill.min.js"); // 一致
}

async function loadPolyfillWithQuote() {
  await import('https://polyfill.io/v3/polyfill.min.js'); // 一致
}

Inside

別のパターンの内側にあるパターンを探す場合に inside を使います。

例: someMethod メソッド内の target 呼び出しを探します。

yaml
inside:
  pattern: public void someMethod($$$){$$$}
pattern: target($$$)

以下のコードが一致します。

java
public class Example {
    public void someMethod(String arg) {
        target("something"); // 一致
    }
}

Metavariable

メタ変数は $ で始めます。

メタ変数の種類 説明
$VAR 一致した AST ノードを VAR に格納
$$$VARS 複数の AST ノードを取得
$$$ 複数行を含む複数のノードに一致

$$$ は次のように複数行のパターンで使えます。

yaml
pattern: |
  public void someMethod($$$) {$$$}

取得したメタ変数の値にもパターンを適用できます。以下のルールは、NOVERIFY がハードコードされた文字列か true の場合に一致します。

yaml
pattern: $JWT.decode($TOKEN, $SECRET, $NOVERIFY, $$$)
metavar:
  name: NOVERIFY
  eq:
    any:
      - pattern: |
          "$$$_STR"
      - pattern: "true"

matcher

matcher は、よく使われる機密情報に関する名前の分類を提供します。複数のルールで password|token|api_key|client_secret... のような大きな正規表現を繰り返す必要がなくなります。

使用できる値:

  • password
  • secret
  • pii
  • sensitive

例:

yaml
metavar:
  name: FIELD
  eq:
    matcher: secret

matcher は名前やキーの形をしたノードから引用符を除き、camelCase、snake_case、kebab-case、ドット区切りの名前、数字の接尾辞をトークンに分けて調べます。大きな式のテキスト全体を機密情報の名前として分類するものではありません。また、実際のメールアドレスや電話番号などの PII 値ではなく、名前やキーを分類します。

regex_pair.left でも使えます。

yaml
regex_pair:
  left:
    matcher: secret
  right: "[0-9a-zA-Z\\-_.=\\~@]{10,150}"

constantValue

JavaScript、TypeScript、TSX でローカルな定数値をたどり、入れ子のルールを適用する場合に constantValue を使います。明示的に指定した場合だけ有効になり、既存の pattern、metavar、resolvedName、taint 解析の動作は変わりません。

基本形:

yaml
constantValue:
  matches: unsafe-origin-value

metavar の下でも同じ形式を使えます。

動作:

  • 最初に現在のノードへ入れ子のルールを直接適用します。
  • ノードが識別子の場合は、最も近いレキシカルスコープの値の束縛を探し、その初期化式へルールを適用します。
  • const、型付きの const、初期化式のある let/var に対応します。ただし、同じスコープ内で再代入される let/var は定数として扱いません。
  • 文字列、数値、Boolean、正規表現のリテラル、引数がリテラルだけの new RegExp(...)、対応する定数式だけで構成した配列やオブジェクト、限定的な識別子の別名チェーンに対応します。
  • JavaScript、TypeScript、TSX 以外では使えません。

例: CORS の origin が危険な正規表現そのもの、またはその正規表現を格納したローカル定数の場合に一致させます。

yaml
utils:
  unsafe-origin-value:
    any:
      - kind: regex
        regex: "[a-zA-Z0-9\\-]\\."
      - all:
          - pattern: new RegExp($PATTERN, $$$)
          - has:
              kind: string
              regex: "[a-zA-Z0-9\\-]\\."

rule:
  pattern: "cors({ origin: $ORIGIN, $$$ })"
  metavar:
    name: ORIGIN
    eq:
      constantValue:
        matches: unsafe-origin-value

以下は origin の初期化式である正規表現リテラルをたどるため一致します。

javascript
const origin = /example\./;
cors({ origin });

以下は origin が再代入されるため、定数値として扱わず一致しません。

javascript
let origin = /example\./;
origin = safeOrigin;
cors({ origin });

import/require で取得した関数やオブジェクトのパッケージを確認する場合は resolvedName を使ってください。引数や設定値に使うローカル定数の初期化式を調べる場合は、constantValue を組み合わせてください。

compare

メタ変数に対する計算や条件の検査に compare を使います。

  • Boolean
  • Number
    • 16 進、2 進、8 進形式(0x、0b、0o など)に対応

例: 権限値の検査。BIT が指定された数値範囲に含まれるかを調べます。

yaml
any:
  - pattern: os.chmod($FILE, $BIT, $$$)
  - pattern: os.fchmod($FILE, $BIT, $$$)
  - pattern: os.lchmod($FILE, $BIT, $$$)
compare: ( $BIT >= 0o650 && $BIT < 0o100000 ) || $BIT >= 0o100650