The Limitations of Heavyweight Legacy SAST
Traditional enterprise Static Application Security Testing (SAST) tools historically earned a reputation for being slow and cumbersome. Engineers spent hours configuring complex build environments, only to wait 45 minutes for a scan that returned hundreds of noisy false positives.
**Semgrep** emerged as a lightweight, fast alternative. By parsing source code directly into language-agnostic Abstract Syntax Trees and querying them using familiar source code patterns, Semgrep executes scans in sub-seconds.
How Semgrep Pattern Matching Works
Instead of learning proprietary query languages (such as Datalog or CodeQL), Semgrep rules resemble the code you are searching for.
Consider searching for insecure instances of Node.js `eval()`:
rules:
- id: no-eval
languages: [javascript, typescript]
message: "Avoid dynamic code execution with eval(); it enables Remote Code Execution (RCE)."
severity: ERROR
pattern: eval(...)The ellipsis operator (`...`) is an abstraction that matches: - Zero or more arguments inside a function call. - Zero or more statements inside a block. - Any arbitrary expressions.
Semgrep recognizes that `eval("console.log('test')")` and `eval(userPayload, extraContext)` both match `pattern: eval(...)`, regardless of formatting, indentation, or comments.
The Power of Metavariables
Metavariables (prefixed with `$`, such as `$USER_INPUT` or `$OBJ`) capture expressions and enforce matching across different locations in code:
# Detect useless self-assignment: x = x
rules:
- id: suspicious-self-assignment
languages: [javascript, typescript, python]
message: "Suspicious self-assignment detected: $VAR is assigned to itself."
severity: WARNING
pattern: $VAR = $VARIf Semgrep encounters `user.age = user.age`, `$VAR` binds to `user.age`, and a vulnerability alert is triggered immediately.
Taint Analysis: Tracing Untrusted Data from Source to Sink
The real power of modern SAST lies in **Taint Tracking**. In web security: - A **Source** is any entry point where untrusted user input enters the system (e.g., `req.query.id`, `req.body`, `request.form`). - A **Sink** is a security-sensitive function where untrusted data could cause harm (e.g., `db.query()`, `eval()`, `res.send()`). - A **Sanitizer** is a function that validates, escapes, or cleans the data (e.g., `parseInt()`, `DOMPurify.sanitize()`).
flowchart LR
Source["Source: req.query.id (Untrusted Input)"] --> Path["Data Flow Path (Propagation)"]
Path --> Sink["Sink: db.query(...) (SQL Injection)"]
Path -. Sanitizer .-> Clean["Sanitizer: parseInt(id) (Safe)"]#### Writing a Taint Rule in Semgrep
Here is an example rule detecting SQL Injection in PostgreSQL queries:
rules:
- id: node-postgres-sqli
languages: [javascript, typescript]
severity: ERROR
message: "Detected potential SQL Injection: untrusted HTTP input reaches raw query string."
mode: taint
pattern-sources:
- pattern: req.query.$PARAM
- pattern: req.body.$PARAM
- pattern: req.params.$PARAM
pattern-sanitizers:
- pattern: parseInt(...)
- pattern: validator.escape(...)
pattern-sinks:
- pattern: db.query($QUERY, ...)
- pattern: client.query($QUERY, ...)When a developer executes:
app.get('/api/users', async (req, res) => {
const userId = req.query.id; // SOURCE
// High risk: Raw string concatenation directly into SQL query!
const query = `SELECT * FROM users WHERE id = '${userId}'`;
const result = await db.query(query); // SINK! Alert triggered!
res.json(result.rows);
});Semgrep traces the tainted variable `userId` from the HTTP request query into the template string and finally into the database query sink.
Integrating Semgrep with DevAudit
The DevAudit container architecture runs an isolated microservice container (`devaudit-semgrep`) that audits pull request diffs and repository snapshots on demand: - **Zero Configuration**: Common rulesets (OWASP Top 10, Secrets, Node.js security) are bundled by default. - **Fast Execution**: Ephemeral checks complete in milliseconds on typical commits. - **Direct Feedback**: Generates actionable annotations that explain both why the defect occurred and how to remediate it.