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
| Scenario | Example |
|---|---|
| Direct source → sink (same statement) | el.innerHTML = req.body.html |
| Single-hop variable assignment | const x = req.body.data; el.innerHTML = x |
| Template literal propagation | const h = `<b>${x}</b>`; el.innerHTML = h |
| String concatenation propagation | const cmd = "ls " + x; exec(cmd) |
| Member access on tainted object | const id = req.params.id; exec("cmd " + id) |
| Sanitizer-through-variable suppression | const s = DOMPurify.sanitize(x); el.innerHTML = s |
| Static variable suppression | const label = "Hello"; el.innerHTML = label |
What is NOT covered (Tier 2 / Tier 3)
| Gap | Reason | Workaround |
|---|---|---|
| Inter-procedural taint — taint flowing through a user-defined function call | Requires building a call graph across functions, which is Tier 2 | Add // 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 modules | Requires a whole-project analysis pass; not practical in a single-file scanner | Same as above |
| Object/array destructuring propagation | const { name } = req.body — destructured properties are not yet tracked | Assign to an intermediate variable before the sink |
| Conditional taint — value is tainted only on certain branches | Flow-sensitive analysis (not implemented) | Unlikely to matter in practice for most XSS/injection sinks |
| Prototype chain / dynamic dispatch | this.input or obj[key] | Use explicit variable assignments |
Practical false negative risk
Because Tier-2 (inter-procedural) taint is not tracked, a pattern like:
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:
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
| Language | AST-based SAST | Taint tracking | Code 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
stringcame fromHTMLElement.innerHTMLor 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 auditexits 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.yamlsha512 checksums) — add"pnpm-lock.yaml"toexclude_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).