Skip to content

SAST Rules Reference

SAST runs automatically when greengate scan encounters a supported source file. It uses tree-sitter to parse each file into a real AST before running any checks.

Supported languages:

LanguageExtensionsFeatures
JavaScript.js, .jsxString-literal scoping, dangerous patterns, code smells, taint tracking
TypeScript.ts, .tsxString-literal scoping, dangerous patterns, code smells, taint tracking
Python.pyString-literal scoping, dangerous patterns
Go.goString-literal scoping, dangerous patterns

Tier-1 intra-procedural taint tracking

GreenGate performs intra-procedural taint tracking for JS/TS to reduce both false positives and false negatives. For every XSS and command-injection sink, the engine resolves where the value came from within the enclosing function body.

How it works

  1. Source seeding — variables assigned from known user-controlled sources are marked tainted:

    Source patternExample
    req.body.*, req.query.*, req.params.*Express route handlers
    request.body.*, request.headers.*Fastify / Koa
    searchParams.get(...)URL search parameters
    localStorage.getItem(...), sessionStorage.getItem(...)Browser storage
    document.cookie, location.hash, location.searchBrowser globals
    event.datapostMessage / worker events
    process.envNode.js environment variables
  2. Fixpoint propagation — taint flows through assignments, template literals, and + concatenation until no new variables are classified.

  3. Safe set — variables assigned from static string/number literals or calls to known sanitizers (DOMPurify.sanitize, JSON.stringify, he.encode, sanitizeHtml, etc.) are marked safe.

Effect on findings

Sink valueResult
Variable in tainted setRule ID gains a [tainted] label — e.g. SAST/InnerHTMLAssignment [tainted] — indicating high-confidence confirmed injection
Variable in safe setFinding is suppressed — value is provably sanitised or static
Unknown variableFinding emitted at normal confidence (unchanged behaviour)
Static string literal (inline)Finding is suppressed
Call to known sanitizer (inline)Finding is suppressed

Suppression rules vs. label-only rules

StrategyRules
Suppress if safe, label if taintedSAST/DangerouslySetInnerHTML, SAST/InnerHTMLAssignment, SAST/OuterHTMLAssignment, SAST/DocumentWrite, SAST/DocumentWriteln, SAST/EvalUsage
Label if tainted, never suppressSAST/ChildProcessExec, SAST/ChildProcessExecSync, SAST/ChildProcessSpawn, SAST/ChildProcessExecFile — a static command name like "bash" is safe by itself but the arguments array may still carry user input

Example

js
// Multi-hop taint chain — detected even across intermediate variables
const raw   = req.body.comment;           // taint source
const html  = `<div>${raw}</div>`;        // propagated: html is tainted
el.innerHTML = html;
// → SAST/InnerHTMLAssignment [tainted]  (high confidence)

// Sanitizer suppresses the finding
const clean = DOMPurify.sanitize(raw);    // clean is marked safe
el.innerHTML = clean;
// → suppressed (provably safe)

// Static variable suppresses the finding
const label = "Enter your name:";
el.innerHTML = label;
// → suppressed (provably safe)

Scope: Tier-1 tracking is intra-procedural only — taint does not follow calls into other functions. See Limitations for details.

Dangerous pattern rules

These rules fire on specific API calls regardless of whether arguments are string literals:

Rule IDWhat it flags
SAST/DangerouslySetInnerHTMLdangerouslySetInnerHTML prop with __html value in TSX/JSX
SAST/InnerHTMLAssignmentelement.innerHTML = expr
SAST/OuterHTMLAssignmentelement.outerHTML = expr
SAST/EvalUsageeval(expr)
SAST/FunctionConstructornew Function(...)
SAST/SetTimeoutStringsetTimeout("code", delay) — string as first argument
SAST/SetIntervalStringsetInterval("code", delay) — string as first argument
SAST/ChildProcessExecchild_process.exec(cmd)
SAST/ChildProcessExecSyncchild_process.execSync(cmd)
SAST/ChildProcessSpawnchild_process.spawn(cmd, args)
SAST/ChildProcessExecFilechild_process.execFile(cmd)
SAST/DocumentWritedocument.write(expr)
SAST/DocumentWritelndocument.writeln(expr)

Python rules

Rule IDWhat it flagsSeverity
SAST/PythonEvaleval(expr) — arbitrary code executioncritical
SAST/PythonExecexec(code) — arbitrary code executioncritical
SAST/PythonPicklepickle.load(f) / pickle.loads(data) — unsafe deserializationhigh
SAST/PythonSubprocessShellAny call with shell=True keyword argument — command injectionhigh
SAST/PythonYamlLoadyaml.load(data) without a Loader= — use yaml.safe_load insteadhigh

Go rules

Rule IDWhat it flagsSeverity
SAST/GoUnsafeimport "unsafe" — direct memory manipulation bypasses type safetyhigh
SAST/GoExecCommandexec.Command(cmd, ...) — possible command injectionhigh
SAST/GoPanicpanic(...) — unexpected process termination in production codemedium

Code smell rules

Rule IDTriggerDefault threshold
SMELL/LongFunctionFunction body exceeds N lines50 lines
SMELL/TooManyParametersFunction has more than N parameters5 params
SMELL/DeepNestingControl-flow depth exceeds N levels inside a function4 levels

Rule IDs embed the measured value — e.g. SMELL/LongFunction (63 lines, max 50) — for immediate context. Thresholds are configurable in .greengate.toml.

Suppressing findings in Python / Go

Use a same-line comment to suppress a specific finding:

python
data = pickle.load(f)  # greengate: ignore
go
panic("fatal: unrecoverable state")  // greengate: ignore

Custom rules

Define project-specific rules using tree-sitter S-expression queries. Each rule must include a @match capture marking the outermost node to report:

toml
[sast]
custom_rules = [
  { id = "CUSTOM/EvalCall", query = "(call_expression function: (identifier) @_fn (#eq? @_fn \"eval\") arguments: (_) @match)" },
  { id = "CUSTOM/FetchCall", query = "(call_expression function: (identifier) @_fn (#eq? @_fn \"fetch\") @match)" },
]

Custom rules are validated at startup — invalid queries are skipped with a warning and never cause greengate to crash.

Disabling rules

toml
[sast]
disabled_rules = [
  "SAST/ChildProcessExec",
  "SAST/DocumentWrite",
  "SMELL/LongFunction",
]

Or disable SAST entirely:

toml
[sast]
enabled = false

Released under the MIT License.