SAST
SAST (Static Application Security Testing) scans source code or compiled binaries for security vulnerabilities without executing the program. Integrated into CI pipelines, tools like Semgrep, SonarQube, and CodeQL catch injection flaws, secrets, and insecure patterns before code reaches production.
Understanding SAST
What Is SAST in Simple Terms
SAST is a security reviewer that reads your code automatically. Instead of waiting for a penetration test or a security audit, SAST runs on every pull request and flags potential vulnerabilities before the code is merged. SQL injection risks, hardcoded passwords, insecure cryptography, path traversal bugs -- SAST catches these at the earliest and cheapest point in the development lifecycle.
At Razorpay, every pull request is scanned by Semgrep before it can be merged. Engineers see security feedback alongside test results -- in the same PR, at the same time.
How It Works
+------------------------------------------+| Source code (PR or commit) |+------------------------------------------+ | v+------------------------------------------+| SAST Tool parses code || Builds AST (Abstract Syntax Tree) || No code execution needed |+------------------------------------------+ | v+------------------------------------------+| Matches patterns against rule sets || Rule: user input reaches SQL query? || Rule: private key in string literal? || Rule: MD5 used for password hashing? |+------------------------------------------+ | v+------------------------------------------+| Findings with severity: INFO/WARN/ERROR || File, line number, explanation || Pass/fail based on severity threshold |+------------------------------------------+SAST in GitHub Actions with Semgrep:
sast-scan: runs-on: ubuntu-latest needs: build steps: - uses: actions/checkout@v4 - name: Run Semgrep SAST uses: semgrep/semgrep-action@v1 with: ## Pre-built rulesets for common vulnerability classes config: > p/nodejs p/secrets p/sql-injection p/xss p/owasp-top-ten ## Generate SARIF for GitHub Security tab generateSarif: true - name: Upload SARIF to GitHub Security tab uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: semgrep.sarif ## CodeQL for deeper analysis (GitHub native) codeql: runs-on: ubuntu-latest permissions: security-events: write steps: - uses: actions/checkout@v4 - uses: github/codeql-action/init@v3 with: languages: javascript - uses: github/codeql-action/autobuild@v3 - uses: github/codeql-action/analyze@v3Semgrep custom rules:
## .semgrep/custom-rules.yaml## Block patterns specific to your codebaserules: ## Catch direct database queries without parameterisation - id: unsafe-query-construction pattern: | db.query("..." + $INPUT) message: | Direct string concatenation in SQL query. Use parameterised queries: db.query(sql, [params]) severity: ERROR languages: [javascript] ## Catch console.log of potentially sensitive objects - id: log-sensitive-data pattern: console.log($REQ.body) message: Logging request body may expose passwords or tokens. severity: WARNING languages: [javascript]Practical Commands
## Install Semgreppip install semgrep ## Run locally before committingsemgrep --config=p/nodejs src/semgrep --config=p/secrets . ## Run with specific rule filesemgrep --config=.semgrep/custom-rules.yaml src/ ## Output JSON for processingsemgrep --config=p/owasp-top-ten --json src/ | \ jq '.results[] | {file: .path, line: .start.line, message: .extra.message}' ## SonarQube scan (if using SonarQube)sonar-scanner \ -Dsonar.projectKey=payment-api \ -Dsonar.sources=src/ \ -Dsonar.host.url=https://sonar.internal \ -Dsonar.token=$SONAR_TOKENTroubleshooting
| Symptom | Check | What to Look For |
|---|---|---|
| Too many false positives | Review rules used | Disable overly broad rules |
| SAST blocking on old code | Baseline file | Semgrep supports baseline to ignore existing findings |
| Scan too slow | Rule count | Use targeted rulesets, not p/all |
TipStart SAST with
p/secretsruleset only. Secret detection has very low false positive rates and catches real critical issues -- API keys, passwords, private keys accidentally committed. Once the team is comfortable with SAST blocking pipelines, gradually add broader rulesets likep/owasp-top-ten.
RememberSAST finds potential vulnerabilities in code -- it does not prove they are exploitable. A SQL injection finding still needs to be reviewed to confirm the input actually reaches the database without sanitisation. SAST is a signal, not a verdict. Triage findings by severity and context.
SecurityConfigure SAST to block only on HIGH and CRITICAL findings. Blocking on MEDIUM and LOW creates noise that causes teams to ignore the scanner entirely. A blocked pipeline with genuine HIGH findings gets fixed. A pipeline blocked every day on INFO findings gets
continue-on-error: trueadded and never gets fixed.
Common MistakeRunning SAST as a reporting-only step that never blocks the pipeline. If SAST findings do not block merges, engineers stop reading them within a week. SAST must be a gate -- HIGH and CRITICAL findings block the PR. This is the only way to ensure findings get fixed rather than accumulated.
Frequently Asked Questions
What kinds of vulnerabilities does SAST catch that a code reviewer typically misses?
SAST tools trace data flow through the actual call graph — following a variable from an untrusted input source through the code to a dangerous sink like a SQL query or shell command — which is tedious and error-prone for a human to verify by eye across a large codebase. It reliably catches classes like SQL injection, hardcoded credentials, path traversal, and insecure deserialization, because these follow detectable patterns even when the vulnerable code path spans multiple files or functions.
Why do teams often end up ignoring SAST findings entirely after a while?
Default SAST rule sets tend to generate a high volume of false positives and low-severity noise, and if a pipeline gate blocks merges on every finding without triage, engineers quickly learn to treat the tool as an obstacle rather than a signal — and start reflexively dismissing alerts, including real ones. The fix is tuning the rule set to the codebase, gating only on high-confidence/high-severity findings, and routing lower-severity results to a dashboard for periodic review instead of blocking every PR.