Semgrep for VPS-Hosted Code: Automated Security Scanning in CI/CD Pipelines
Semgrep is a fast, open-source static analysis tool for finding security vulnerabilities in code — SQL injection, XSS, hardcoded secrets, insecure cryptography, and 2,000+ other patterns across 30+ languages. Unlike complex tools like SonarQube (Java server, 2+ GB RAM), Semgrep is a CLI tool that runs in seconds on any CI/CD pipeline. Integrating it into your VPS-hosted CI/CD prevents security vulnerabilities from reaching production.
Semgrep vs SonarQube vs CodeQL
- Semgrep: Fast CLI, 30+ languages, open rule registry, easy custom rules, minimal setup
- SonarQube: Web server (2+ GB RAM), broad metrics (coverage, duplication, complexity), CI integration
- CodeQL: GitHub-owned, deep analysis, slower, best for complex vulnerability detection
- Choose Semgrep: Fast security scanning in CI, custom rule writing, polyglot codebases, minimal overhead
Step 1: Install Semgrep
<code"># Install Semgrep pip install semgrep # Or via package manager: brew install semgrep # macOS # Verify semgrep --version # Run a quick scan (uses recommended security ruleset): semgrep --config=auto /path/to/your/code
Step 2: Run Your First Security Scan
<code"># Scan with OWASP Top 10 rules:
semgrep --config "p/owasp-top-ten" ./src/
# Scan for Python security issues:
semgrep --config "p/python-security" ./
# Scan for JavaScript/Node.js vulnerabilities:
semgrep --config "p/javascript-node-security" ./
# Scan for secrets (API keys, passwords in code):
semgrep --config "p/secrets" ./
# Scan for multiple rulesets at once:
semgrep \
--config "p/owasp-top-ten" \
--config "p/secrets" \
--config "p/sql-injection" \
--output results.json \
--json \
./src/
Step 3: Understanding Results
<code"># Sample Semgrep output:
# Path/file.py
# Rule ID: python.lang.security.audit.sql.avoid-sql-injection
# Severity: ERROR
# Line 45: cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
# Message: SQL injection vulnerability — use parameterized queries
# Severity levels:
# ERROR — high-confidence vulnerability, should block deployment
# WARNING — potential vulnerability, review required
# INFO — informational, coding practice improvement
# Fix the SQL injection:
# BEFORE: cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
# AFTER: cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
Step 4: Write Custom Rules
<code"># Custom rule to detect hardcoded API keys:
# /opt/semgrep-rules/no-hardcoded-keys.yaml
rules:
- id: no-hardcoded-api-key
patterns:
- pattern: |
$VAR = "sk-..."
- pattern: |
API_KEY = "..."
- pattern: |
$VAR = "Bearer ..."
message: "Hardcoded API key detected — use environment variables instead"
languages: [python, javascript, typescript, go]
severity: ERROR
metadata:
category: security
technology: [secrets]
- id: no-debug-print-credentials
patterns:
- pattern: print($X.password)
- pattern: console.log($X.password)
- pattern: fmt.Println($X.password)
message: "Logging credential — remove this before deployment"
languages: [python, javascript, go]
severity: WARNING
- id: require-csrf-decorator
pattern: |
@app.route(...)
def $FUNC(...):
...
pattern-not: |
@csrf_protect
@app.route(...)
def $FUNC(...):
...
message: "Flask route missing @csrf_protect decorator"
languages: [python]
severity: WARNING
<code"># Run with custom rules: semgrep --config /opt/semgrep-rules/ ./src/
Step 5: Integrate with Gitea Actions
<code"># .gitea/workflows/security-scan.yml
name: Security Scan
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
semgrep:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Semgrep
run: pip install semgrep
- name: Run Semgrep Security Scan
run: |
semgrep \
--config "p/owasp-top-ten" \
--config "p/secrets" \
--config "p/python-security" \
--error \ # Exit with error code if any findings
--json \
--output semgrep-results.json \
./src/
- name: Upload results
if: always()
uses: actions/upload-artifact@v3
with:
name: semgrep-results
path: semgrep-results.json
- name: Comment on PR (if findings)
if: failure() && github.event_name == 'pull_request'
run: |
FINDINGS=$(python3 -c "
import json
with open('semgrep-results.json') as f:
results = json.load(f)
errors = [r for r in results['results'] if r['extra']['severity'] == 'ERROR']
print(f'{len(errors)} security findings require attention')
")
echo "$FINDINGS"
Step 6: GitHub Actions Integration
<code"># .github/workflows/semgrep.yml
name: Semgrep
on:
push:
branches: ["main"]
pull_request: {}
schedule:
- cron: '0 6 * * 1' # Weekly Monday 6 AM scan
jobs:
semgrep:
name: semgrep/ci
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
steps:
- uses: actions/checkout@v4
- name: Run Semgrep
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} # Optional: for Semgrep Cloud
run: |
semgrep ci \
--config "p/owasp-top-ten" \
--config "p/secrets" \
--error
Step 7: Scan Pre-commit (Catch Issues Before Commit)
<code"># Install pre-commit
pip install pre-commit
# .pre-commit-config.yaml in your repo root:
repos:
- repo: https://github.com/returntocorp/semgrep
rev: v1.60.0
hooks:
- id: semgrep
args: ['--config', 'p/secrets', '--config', 'p/python-security', '--error']
<code"># Enable pre-commit hooks: pre-commit install # Now every git commit automatically runs Semgrep: git commit -m "Add database query" # [Semgrep scanning...] # ERROR: SQL injection detected at src/db.py:45 # Commit aborted — fix the issue first
Getting Started
Semgrep runs in your CI pipeline as a CLI tool — no server infrastructure needed beyond your VPS-hosted Gitea or GitHub Actions runner. On a standard Ubuntu VPS at VPS.DO running your CI, Semgrep scans a 100,000-line Python/JavaScript codebase in 10–30 seconds. The OWASP Top 10 and secrets rulesets together catch the highest-impact vulnerability categories with very low false positive rates.
Conclusion
Semgrep provides fast, lightweight SAST (Static Application Security Testing) that integrates into any CI/CD pipeline in minutes — no separate server, no Java runtime, no complex configuration. Running OWASP Top 10 and secrets rulesets on every pull request catches SQL injection, XSS, hardcoded API keys, and other critical vulnerabilities before they reach production. Custom rules encode your organization’s security policies as code, automatically enforced on every commit. For VPS-hosted development teams, Semgrep in CI is the highest-ROI security investment after dependency scanning.