# Static Application Security Testing (SAST) — DevSecOps

Source: https://www.skillbyai.com/en/devsecops/dso-sast

> Explain how SAST tools analyse source code, run Semgrep or CodeQL in CI, and handle false positives sensibly.

## Reading code without running it

**SAST** tools analyse source code (or bytecode) without executing it, looking for insecure patterns. Simple rules match syntax, such as a call to `eval` or `yaml.load` without a safe loader. Stronger engines perform **taint analysis**: they mark data from **sources** (request parameters, headers, files) and track it through assignments and function calls to **sinks** (SQL execution, shell commands, HTML output). If tainted data reaches a sink without passing a **sanitiser**, that is a finding. Common tools include **Semgrep** (fast, readable rules in YAML), **CodeQL** (queries over a database built from your code, integrated with GitHub code scanning) and language-specific linters like Bandit for Python. SAST runs early and covers every code path, but it does not know runtime configuration, so it produces **false positives** (flagged code that is safe) and **false negatives** (real bugs it cannot model, such as business-logic flaws).

## Three lenses on your code and dependencies

Static analysis looks at the code you wrote, composition analysis looks at the packages you pulled in, and the SBOM records the full inventory so you can answer 'are we affected?' later.

![Three connected stages: SAST on first-party code, SCA on dependencies, SBOM inventory.](assets/figures/devsecops/section-5-map.svg) — Figure 5.1: SAST (your code) -> SCA (your dependencies) -> SBOM (your inventory).

## A custom Semgrep rule and a CI invocation

The rule flags `subprocess` calls with `shell=True`. In CI, `--error` makes Semgrep exit non-zero when it finds something, which fails the job.

```yaml
# .semgrep/shell-true.yaml
rules:
  - id: subprocess-shell-true
    languages: [python]
    severity: ERROR
    message: Avoid shell=True; pass an argument list instead.
    pattern: subprocess.$FUNC(..., shell=True, ...)

# CI step (GitHub Actions):
#   - run: semgrep scan --config .semgrep/ --config p/python --error
```

## Scan the diff, report the baseline

On a legacy codebase the first scan may show hundreds of findings. Block pull requests only on **new** findings in changed code, and burn down the existing backlog separately; otherwise teams disable the tool.

**Quiz:** In taint analysis, what is a "sink"?

- [ ] The place where untrusted data enters the program
- [ ] A function that cleans data
- [x] A sensitive operation, such as executing SQL, that tainted data must not reach unsanitised
- [ ] A log file that stores scan results

*Answer:* A sensitive operation, such as executing SQL, that tainted data must not reach unsanitised. Sources introduce untrusted data, sanitisers clean it, and sinks are dangerous operations where unsanitised data causes vulnerabilities.
