// Engineering Log

Secure Development: Part 3 — SAST: Static Code Analysis

Published on 2026-09-22

// Fast route

This article belongs to the topic Security and protection.

An experienced developer finds vulnerabilities in someone else’s code by familiar signs: user data goes straight into an SQL query, a password is compared with plain ==, a file path is constructed from a request parameter. But a person cannot review a hundred thousand lines and not miss anything. SAST takes this work on.

What is SAST

SAST (Static Application Security Testing, static security analysis) — checking source code without running the application. The analyzer parses the code into a syntax tree and looks for dangerous constructs.

The main technique is data flow analysis (taint analysis). The analyzer marks “sources” — places where untrusted data comes from: request parameters, headers, form bodies. Then it traces whether that data reaches a “sink” — a dangerous function like executing SQL, running a shell command, or writing into HTML — without passing through sanitization or escaping. If it does, a warning appears.

This work is not replaced by tests. A test checks that when you enter the name Ivan the database records Ivan. SAST checks what happens if the name is ' OR 1=1 --, even though the code functionally works correctly.

Example: SQL injection

python
@app.route("/user")
def get_user():
    user_id = request.args.get("id")
    # dangerous: value from the request is inserted into the query string
    query = "SELECT * FROM users WHERE id = %s" % user_id
    db.execute(query)

An analyzer rule describes exactly this situation: a value from request via string formatting reaches execute(). The fix is a parameterized query: db.execute("SELECT * FROM users WHERE id = %s", (user_id,)). The DB driver sends the value separately from the query text, and injection becomes impossible.

Tools

Semgrep

Semgrep is the most common lightweight scanner. Rules are written in YAML almost in the language of the code itself, so you can create your own project rule in a few minutes.

It’s important to understand its licensing. The Semgrep Community Edition engine is distributed under LGPL-2.1 and is free. But its capabilities are limited: according to Semgrep documentation, the open version analyzes interactions only within a single function. Cross-function and cross-file analysis is available in the commercial product Semgrep Code. The rules supported by the company itself are distributed under their own license: they can be used for internal tasks, but cannot be embedded in competing products and services.

Opengrep

When Semgrep moved some features to a commercial license, a group of companies created the Opengrep fork. It is distributed under LGPL-2.1, is compatible with Semgrep rules, and advances data flow analysis in an open form. If it’s important that the tool remain fully open, Opengrep is a natural replacement.

SonarQube Community Build

SonarQube is a platform that combines vulnerability detection with code quality checks: duplication, complexity, test coverage. The free Community Build edition is distributed under LGPL-3.0 and is installed on your own server. For a small team this is a convenient option if you need a project-wide report, not just a scanner in CI.

CodeQL

CodeQL from GitHub models code as a database that you query. It’s one of the most in-depth analyzers. For public repositories on GitHub, code scanning is enabled for free. For private repositories you need the paid GitHub Code Security product, and its availability and payment for a Russian company should be checked separately.

How to run locally

Semgrep is installed via pip or Homebrew:

bash
pip install semgrep
semgrep scan --config p/python

p/python is a ready-made set of rules for Python from the Semgrep registry. For JavaScript there is p/javascript, for general checks — p/default. Opengrep is installed with a script from the project repository and accepts the same rules.

SAST in CI

It makes sense to run the check on every pull request: a vulnerability found before merging is cheapest to fix. Example job for GitHub Actions using the official Semgrep image:

yaml
name: sast
on: [pull_request]

jobs:
  semgrep:
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    steps:
      - uses: actions/checkout@v4
      - run: semgrep scan --config p/python --error

The --error flag exits with an error if issues are found, and the CI prevents merging the code. The old semgrep-action wrapper is deprecated, so Semgrep is run directly as in the example. In GitLab CI the same is done with a job using the same image.

To avoid drowning in old findings, start in a mode that only checks changed code, or first collect a baseline report and agree that new warnings are forbidden while old ones are addressed gradually.

False positives

No analyzer is completely accurate: sometimes safe code is flagged as dangerous.

  • Rule tuning. An overly strict rule can be disabled or refined for the project.
  • On-site suppression. A # nosemgrep comment above the line disables the check for it. You should explain next to it why the code is safe, otherwise no one will remember in six months.
  • Triage. Someone on the team is responsible for reports and marks findings as “to fix” or “false positive”.

If suppressions become numerous, that’s a signal to review the rule set, not to get used to the noise.

Where to start

  1. Run Semgrep or Opengrep on your project once and analyze findings at the ERROR level.
  2. Add the check to CI on pull requests, initially only for new warnings.
  3. Write one or two custom rules for the typical mistakes in your project: that’s the fastest way to get value that general rule sets won’t provide.

// Similar task

If you are dealing with something similar

This article belongs to one of the main working topics. You can keep reading on the topic, go to the homepage to understand what I do, or open the service pages directly.

Article topic

Security and protection

SSL, hardening, access control, service protection, and secure configurations.

Typical tasks behind this topic

  • Set up SSL, certificates, and secure connections
  • Restrict access and close unnecessary entry points
  • Harden server and service configuration

// Next step

If you need help with this topic, not just another article, it is better to go straight to the service page. The homepage and topic collection stay available as secondary routes.

Open services

// Contact

Need help?

Get in touch with me and I'll help solve the problem

I reply within one business day (03:00-13:00 GMT)

Или оставьте заявку здесь:

Confirm that you are not a bot.

Write and get a quick reply