any/all
| 필드 | 설명 |
|---|---|
| any | 여러 조건 중 하나만 충족해도 될 때 사용 |
| all | 나열한 모든 조건을 충족해야 할 때 사용 |
예제 1: method_1 또는 method_2 중 하나에 일치하는 호출을 찾습니다.
any:
- pattern: method_1($$$)
- pattern: method_2($$$)
예제 2:
all:
- pattern: method_1($$$)
- inside:
pattern: $F(async ($REQ, $RES) => {$$$})
- inside:
pattern: for($IN = $S; $$$; $$$) {$$$}
not
특정 패턴을 제외하고 싶을때 사용
pattern: $REQ.META
not:
inside:
any:
- pattern: $REQ.META.CONTENT_LENGTH
- pattern: $REQ.META.CONTENT_TYPE
regex
regex 기반으로 매칭을 제공
예제: polyfill.io url 탐지
메타변수 STR에 저장한 문자열을 정규식으로 검사합니다.
pattern: |
"$STR"
metavar:
name: STR
eq:
regex: '(?:https?:)?//(?:[^/]*\.)?polyfill\.io'
아래 코드와 같이 탐지
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
패턴 내 패턴을 탐지할때 사용
예제: someMethod 함수 내 target 함수 사용 탐지
inside:
pattern: public void someMethod($$$){$$$}
pattern: target($$$)
아래 코드와 같이 탐지
public class Example {
public void someMethod(String arg) {
target("something"); // 탐지
}
}
Metavariable
$를 prefix로 사용
| Metavariable 유형 | 설명 |
|---|---|
| $VAR | 일치한 AST 노드를 VAR에 저장 |
| $$$VARS | 여러개의 AST 노드들을 탐지하고 싶을 시 사용 |
| $$$ | 여러 줄을 포함하여 탐지하고 싶을 시 사용 |
$$$은 아래와 같이 사용하여 multi-line 패턴을 탐지할 수 있음
pattern: |
public void someMethod($$$) {$$$}
Metavariable로 추출한 값들에 대해 아래와 같이 패턴 매칭 또한 가능함
아래 룰은 NOVERIFY가 하드코딩된 문자열이거나 true일 경우를 탐지
pattern: $JWT.decode($TOKEN, $SECRET, $NOVERIFY, $$$)
metavar:
name: NOVERIFY
eq:
any:
- pattern: |
"$$$_STR"
- pattern: "true"
matcher
matcher는 자주 사용하는 민감 이름 분류를 엔진에서 제공하는 atomic matcher입니다. 여러 룰에 password|token|api_key|client_secret... 형태의 큰 regex를 반복해서 넣지 않아도 됩니다.
지원 값:
passwordsecretpiisensitive
예:
metavar:
name: FIELD
eq:
matcher: secret
matcher는 이름/key 형태의 노드에서 quote를 제거하고 camelCase, snake_case, kebab-case, dotted name, 숫자 suffix를 token 단위로 나누어 검사합니다. 큰 expression 전체 텍스트를 민감 이름으로 분류하지 않으며, 실제 이메일 주소나 전화번호 같은 literal PII 값 탐지가 아니라 이름/key 분류용입니다.
regex_pair.left에서도 사용할 수 있습니다.
regex_pair:
left:
matcher: secret
right: "[0-9a-zA-Z\\-_.=\\~@]{10,150}"
constantValue
constantValue는 JavaScript, TypeScript, TSX에서 로컬 상수 값까지 따라가서 중첩 룰을 검사할 때 사용합니다. 기존 pattern, metavar, resolvedName, taint 분석 동작은 변경하지 않으며, 룰에서 명시적으로 constantValue를 사용할 때만 활성화됩니다.
기본 형태:
constantValue:
matches: unsafe-origin-value
metavar 아래에서도 동일하게 사용할 수 있습니다.
동작 방식:
- 현재 노드에 중첩 룰을 먼저 직접 적용합니다.
- 현재 노드가 identifier이면 가장 가까운 lexical scope의 value binding을 찾고, 해당 initializer 노드에 중첩 룰을 적용합니다.
const, typedconst, initializer가 있는let/var를 지원합니다. 단, 같은 scope에서 재할당되는let/var는 상수로 취급하지 않습니다.- 문자열, 숫자, boolean, regex literal, literal 인자만 사용하는
new RegExp(...), 지원되는 상수 표현식으로만 구성된 array/object, 제한된 identifier alias chain을 지원합니다. - JavaScript, TypeScript, TSX 외 언어에서는 사용할 수 없습니다.
예제: CORS origin 값이 직접 unsafe regex이거나, 로컬 상수로 분리된 unsafe regex일 때 탐지
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의 initializer인 regex literal을 따라가므로 탐지됩니다.
const origin = /example\./;
cors({ origin });
아래 코드는 origin이 재할당되므로 상수 값으로 취급하지 않아 탐지하지 않습니다.
let origin = /example\./;
origin = safeOrigin;
cors({ origin });
import/require로 가져온 함수나 객체가 특정 패키지인지 확인할 때는 resolvedName을 사용하고, 함수 인자나 설정 값처럼 로컬 상수 initializer를 검사해야 할 때 constantValue를 함께 사용합니다.
compare
Metavariable에 대한 계산 관련 조건 검사할 때 사용
- Boolean
- Number
- Hex, Binary, Octal 지원 (예:
0x,0b,0o)
- Hex, Binary, Octal 지원 (예:
예제: 권한 검사
아래와 같이 BIT에 특정 range 내 포함되는지 확인할때 유용하게 사용 가능
any:
- pattern: os.chmod($FILE, $BIT, $$$)
- pattern: os.fchmod($FILE, $BIT, $$$)
- pattern: os.lchmod($FILE, $BIT, $$$)
compare: ( $BIT >= 0o650 && $BIT < 0o100000 ) || $BIT >= 0o100650