Skip to content

Limitations

This page documents the known boundaries of GreenGate's analysis. Understanding these limitations helps you set accurate expectations and decide where additional tooling may be warranted.


SAST — taint tracking scope

GreenGate implements Tier-1 intra-procedural taint tracking for JS/TS. This means:

What IS covered

ScenarioExample
Direct source → sink (same statement)el.innerHTML = req.body.html
Single-hop variable assignmentconst x = req.body.data; el.innerHTML = x
Template literal propagationconst h = `<b>${x}</b>`; el.innerHTML = h
String concatenation propagationconst cmd = "ls " + x; exec(cmd)
Member access on tainted objectconst id = req.params.id; exec("cmd " + id)
Sanitizer-through-variable suppressionconst s = DOMPurify.sanitize(x); el.innerHTML = s
Static variable suppressionconst label = "Hello"; el.innerHTML = label

What is NOT covered (Tier 2 / Tier 3)

GapReasonWorkaround
Inter-procedural taint — taint flowing through a user-defined function callRequires building a call graph across functions, which is Tier 2Add // greengate: ignore on the call site, or use a purpose-built SAST tool (Semgrep, Snyk Code) for this pattern
Cross-file taint — taint flowing through import/require across modulesRequires a whole-project analysis pass; not practical in a single-file scannerSame as above
Object/array destructuring propagationconst { name } = req.body — destructured properties are not yet trackedAssign to an intermediate variable before the sink
Conditional taint — value is tainted only on certain branchesFlow-sensitive analysis (not implemented)Unlikely to matter in practice for most XSS/injection sinks
Prototype chain / dynamic dispatchthis.input or obj[key]Use explicit variable assignments

Practical false negative risk

Because Tier-2 (inter-procedural) taint is not tracked, a pattern like:

js
function getInput() {
  return req.body.data;   // taint source inside a helper
}

el.innerHTML = getInput();  // greengate sees an unknown call — flags normally

…is still flagged at normal confidence because GreenGate does not know getInput() is safe. The false negative scenario is the opposite: a sanitizer wrapped in a function will NOT suppress the finding:

js
function safeHtml(input) {
  return DOMPurify.sanitize(input);  // safe inside function
}

el.innerHTML = safeHtml(raw);  // greengate does not know safeHtml() is safe
                               // → flagged (false positive)

For this case, use // greengate: ignore on the assignment line, or add safeHtml to a custom-safe list via a custom SAST rule.


SAST — language coverage

LanguageAST-based SASTTaint trackingCode smells
JavaScript (.js, .jsx)
TypeScript (.ts, .tsx)
Python (.py)
Go (.go)
Ruby, PHP, Java, C#, Rust

Python and Go SAST uses pattern-only matching (no taint tracking). Taint tracking is JS/TS only.


SAST — no TypeScript type information

GreenGate uses tree-sitter for AST parsing. tree-sitter is a syntax parser — it does not have access to TypeScript's type checker. This means:

  • The engine cannot know the declared type of a variable (e.g. it cannot tell whether a string came from HTMLElement.innerHTML or a user-defined getter).
  • Generic suppression decisions (is this exec() a child_process call or a DB query builder call?) are made by inspecting the receiver's name and AST shape, not its type.

For higher-fidelity type-aware analysis, Semgrep Pro or a dedicated type-aware linter would be needed.


Dependency audit — OSV API dependency

greengate audit queries the OSV database. In environments without outbound internet access:

  • Audit results are cached locally for 24 hours (offline-friendly for most CI scenarios).
  • If the cache is stale and the network is unavailable, greengate audit exits with a warning rather than a hard failure, so it does not break air-gapped builds.

ignore_advisories in .greengate.toml suppresses specific GHSA/CVE IDs without disabling the audit entirely. See the audit command docs for details.


Secret scanning — entropy tuning

Shannon entropy detection (entropy = true) may produce false positives on:

  • Lock file integrity hashes (e.g. pnpm-lock.yaml sha512 checksums) — add "pnpm-lock.yaml" to exclude_patterns.
  • Base64-encoded binary assets embedded in source (SVGs, fonts) — exclude **/public/** or the specific asset directory.
  • Minified JavaScript — exclude **/*.min.js.

Raising entropy_threshold (e.g. to 5.0) reduces false positives but may miss shorter secrets. Lowering it (e.g. to 3.5) via --profile strict increases sensitivity.


Baseline mode

--since-baseline compares findings against .greengate-baseline.json. Findings are matched by file path + rule ID + line number. If a secret moves to a different line (e.g. after a rebase or auto-formatter pass), it will re-appear as a new finding. Commit .greengate-baseline.json to version control and regenerate it with --update-baseline whenever baseline findings are intentionally resolved.


No inter-process or runtime analysis

GreenGate is a static analysis tool. It cannot:

  • Detect secrets injected at runtime via environment variables (those are generally safe — use env vars instead of hardcoding).
  • Detect vulnerabilities that only manifest under specific runtime conditions (race conditions, logic bugs, SSRF depending on user-controlled URLs at runtime).
  • Replace dynamic analysis tools (DAST, fuzzing, penetration testing).

Released under the MIT License.