security-scanning-security-sast

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SAST Security Plugin

SAST安全插件

Static Application Security Testing (SAST) for comprehensive code vulnerability detection across multiple languages, frameworks, and security patterns.
静态应用安全测试(SAST):全面检测多语言、多框架及各类安全场景下的代码漏洞。

Capabilities

功能特性

  • Multi-language SAST: Python, JavaScript/TypeScript, Java, Ruby, PHP, Go, Rust
  • Tool integration: Bandit, Semgrep, ESLint Security, SonarQube, CodeQL, PMD, SpotBugs, Brakeman, gosec, cargo-clippy
  • Vulnerability patterns: SQL injection, XSS, hardcoded secrets, path traversal, IDOR, CSRF, insecure deserialization
  • Framework analysis: Django, Flask, React, Express, Spring Boot, Rails, Laravel
  • Custom rule authoring: Semgrep pattern development for organization-specific security policies
  • 多语言SAST支持:Python、JavaScript/TypeScript、Java、Ruby、PHP、Go、Rust
  • 工具集成:Bandit、Semgrep、ESLint Security、SonarQube、CodeQL、PMD、SpotBugs、Brakeman、gosec、cargo-clippy
  • 漏洞检测类型:SQL注入、XSS、硬编码密钥、路径遍历、IDOR、CSRF、不安全反序列化
  • 框架分析:Django、Flask、React、Express、Spring Boot、Rails、Laravel
  • 自定义规则编写:基于Semgrep开发符合组织特定安全策略的检测规则

Use this skill when

适用场景

Use for code review security analysis, injection vulnerabilities, hardcoded secrets, framework-specific patterns, custom security policy enforcement, pre-deployment validation, legacy code assessment, and compliance (OWASP, PCI-DSS, SOC2).
Specialized tools: Use
security-secrets.md
for advanced credential scanning,
security-owasp.md
for Top 10 mapping,
security-api.md
for REST/GraphQL endpoints.
用于代码评审安全分析、注入漏洞检测、硬编码密钥排查、框架特定安全模式检查、自定义安全策略执行、部署前验证、遗留代码评估及合规性检查(OWASP、PCI-DSS、SOC2)。
专属工具:如需高级凭证扫描,请使用
security-secrets.md
;如需OWASP Top 10映射,请使用
security-owasp.md
;如需REST/GraphQL端点测试,请使用
security-api.md

Do not use this skill when

不适用场景

  • You only need runtime testing or penetration testing
  • You cannot access the source code or build outputs
  • The environment forbids third-party scanning tools
  • 仅需运行时测试或渗透测试时
  • 无法访问源代码或构建输出时
  • 环境禁止使用第三方扫描工具时

Instructions

操作步骤

  1. Identify the languages, frameworks, and scope to scan.
  2. Select SAST tools and configure rules for the codebase.
  3. Run scans in CI or locally with reproducible settings.
  4. Triage findings, prioritize by severity, and propose fixes.
  1. 确定待扫描的语言、框架及范围。
  2. 选择SAST工具并针对代码库配置规则。
  3. 在CI环境或本地以可复现的设置运行扫描。
  4. 分类处理检测结果,按严重程度优先排序并提出修复方案。

Safety

安全注意事项

  • Avoid uploading proprietary code to external services without approval.
  • Require review before enabling auto-fix or blocking releases.
  • 未经批准,请勿将专有代码上传至外部服务。
  • 在启用自动修复或阻止发布前,需经过审核。

SAST Tool Selection

SAST工具选择

Python: Bandit

Python: Bandit

bash
undefined
bash
undefined

Installation & scan

Installation & scan

pip install bandit bandit -r . -f json -o bandit-report.json bandit -r . -ll -ii -f json # High/Critical only

**Configuration**: `.bandit`
```yaml
exclude_dirs: ['/tests/', '/venv/', '/.tox/', '/build/']
tests: [B201, B301, B302, B303, B304, B305, B307, B308, B312, B323, B324, B501, B502, B506, B602, B608]
skips: [B101]
pip install bandit bandit -r . -f json -o bandit-report.json bandit -r . -ll -ii -f json # High/Critical only

**Configuration**: `.bandit`
```yaml
exclude_dirs: ['/tests/', '/venv/', '/.tox/', '/build/']
tests: [B201, B301, B302, B303, B304, B305, B307, B308, B312, B323, B324, B501, B502, B506, B602, B608]
skips: [B101]

JavaScript/TypeScript: ESLint Security

JavaScript/TypeScript: ESLint Security

bash
npm install --save-dev eslint @eslint/plugin-security eslint-plugin-no-secrets
eslint . --ext .js,.jsx,.ts,.tsx --format json > eslint-security.json
Configuration:
.eslintrc-security.json
json
{
  "plugins": ["@eslint/plugin-security", "eslint-plugin-no-secrets"],
  "extends": ["plugin:security/recommended"],
  "rules": {
    "security/detect-object-injection": "error",
    "security/detect-non-literal-fs-filename": "error",
    "security/detect-eval-with-expression": "error",
    "security/detect-pseudo-random-prng": "error",
    "no-secrets/no-secrets": "error"
  }
}
bash
npm install --save-dev eslint @eslint/plugin-security eslint-plugin-no-secrets
eslint . --ext .js,.jsx,.ts,.tsx --format json > eslint-security.json
Configuration:
.eslintrc-security.json
json
{
  "plugins": ["@eslint/plugin-security", "eslint-plugin-no-secrets"],
  "extends": ["plugin:security/recommended"],
  "rules": {
    "security/detect-object-injection": "error",
    "security/detect-non-literal-fs-filename": "error",
    "security/detect-eval-with-expression": "error",
    "security/detect-pseudo-random-prng": "error",
    "no-secrets/no-secrets": "error"
  }
}

Multi-Language: Semgrep

Multi-Language: Semgrep

bash
pip install semgrep
semgrep --config=auto --json --output=semgrep-report.json
semgrep --config=p/security-audit --json
semgrep --config=p/owasp-top-ten --json
semgrep ci --config=auto  # CI mode
Custom Rules:
.semgrep.yml
yaml
rules:
  - id: sql-injection-format-string
    pattern: cursor.execute("... %s ..." % $VAR)
    message: SQL injection via string formatting
    severity: ERROR
    languages: [python]
    metadata:
      cwe: "CWE-89"
      owasp: "A03:2021-Injection"

  - id: dangerous-innerHTML
    pattern: $ELEM.innerHTML = $VAR
    message: XSS via innerHTML assignment
    severity: ERROR
    languages: [javascript, typescript]
    metadata:
      cwe: "CWE-79"

  - id: hardcoded-aws-credentials
    patterns:
      - pattern: $KEY = "AKIA..."
      - metavariable-regex:
          metavariable: $KEY
          regex: "(aws_access_key_id|AWS_ACCESS_KEY_ID)"
    message: Hardcoded AWS credentials detected
    severity: ERROR
    languages: [python, javascript, java]

  - id: path-traversal-open
    patterns:
      - pattern: open($PATH, ...)
      - pattern-not: open(os.path.join(SAFE_DIR, ...), ...)
      - metavariable-pattern:
          metavariable: $PATH
          patterns:
            - pattern: $REQ.get(...)
    message: Path traversal via user input
    severity: ERROR
    languages: [python]

  - id: command-injection
    patterns:
      - pattern-either:
          - pattern: os.system($CMD)
          - pattern: subprocess.call($CMD, shell=True)
      - metavariable-pattern:
          metavariable: $CMD
          patterns:
            - pattern-either:
                - pattern: $X + $Y
                - pattern: f"...{$VAR}..."
    message: Command injection via shell=True
    severity: ERROR
    languages: [python]
bash
pip install semgrep
semgrep --config=auto --json --output=semgrep-report.json
semgrep --config=p/security-audit --json
semgrep --config=p/owasp-top-ten --json
semgrep ci --config=auto  # CI mode
Custom Rules:
.semgrep.yml
yaml
rules:
  - id: sql-injection-format-string
    pattern: cursor.execute("... %s ..." % $VAR)
    message: SQL injection via string formatting
    severity: ERROR
    languages: [python]
    metadata:
      cwe: "CWE-89"
      owasp: "A03:2021-Injection"

  - id: dangerous-innerHTML
    pattern: $ELEM.innerHTML = $VAR
    message: XSS via innerHTML assignment
    severity: ERROR
    languages: [javascript, typescript]
    metadata:
      cwe: "CWE-79"

  - id: hardcoded-aws-credentials
    patterns:
      - pattern: $KEY = "AKIA..."
      - metavariable-regex:
          metavariable: $KEY
          regex: "(aws_access_key_id|AWS_ACCESS_KEY_ID)"
    message: Hardcoded AWS credentials detected
    severity: ERROR
    languages: [python, javascript, java]

  - id: path-traversal-open
    patterns:
      - pattern: open($PATH, ...)
      - pattern-not: open(os.path.join(SAFE_DIR, ...), ...)
      - metavariable-pattern:
          metavariable: $PATH
          patterns:
            - pattern: $REQ.get(...)
    message: Path traversal via user input
    severity: ERROR
    languages: [python]

  - id: command-injection
    patterns:
      - pattern-either:
          - pattern: os.system($CMD)
          - pattern: subprocess.call($CMD, shell=True)
      - metavariable-pattern:
          metavariable: $CMD
          patterns:
            - pattern-either:
                - pattern: $X + $Y
                - pattern: f"...{$VAR}..."
    message: Command injection via shell=True
    severity: ERROR
    languages: [python]

Other Language Tools

Other Language Tools

Java:
mvn spotbugs:check
Ruby:
brakeman -o report.json -f json
Go:
gosec -fmt=json -out=gosec.json ./...
Rust:
cargo clippy -- -W clippy::unwrap_used
Java:
mvn spotbugs:check
Ruby:
brakeman -o report.json -f json
Go:
gosec -fmt=json -out=gosec.json ./...
Rust:
cargo clippy -- -W clippy::unwrap_used

Vulnerability Patterns

漏洞检测类型

SQL Injection

SQL注入

VULNERABLE: String formatting/concatenation with user input in SQL queries
SECURE:
python
undefined
VULNERABLE: String formatting/concatenation with user input in SQL queries
SECURE:
python
undefined

Parameterized queries

Parameterized queries

cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) User.objects.filter(id=user_id) # ORM
undefined
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) User.objects.filter(id=user_id) # ORM
undefined

Cross-Site Scripting (XSS)

跨站脚本攻击(XSS)

VULNERABLE: Direct HTML manipulation with unsanitized user input (innerHTML, outerHTML, document.write)
SECURE:
javascript
// Use textContent for plain text
element.textContent = userInput;

// React auto-escapes
<div>{userInput}</div>

// Sanitize when HTML required
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
VULNERABLE: Direct HTML manipulation with unsanitized user input (innerHTML, outerHTML, document.write)
SECURE:
javascript
// Use textContent for plain text
element.textContent = userInput;

// React auto-escapes
<div>{userInput}</div>

// Sanitize when HTML required
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);

Hardcoded Secrets

硬编码密钥

VULNERABLE: Hardcoded API keys, passwords, tokens in source code
SECURE:
python
import os
API_KEY = os.environ.get('API_KEY')
PASSWORD = os.getenv('DB_PASSWORD')
VULNERABLE: Hardcoded API keys, passwords, tokens in source code
SECURE:
python
import os
API_KEY = os.environ.get('API_KEY')
PASSWORD = os.getenv('DB_PASSWORD')

Path Traversal

路径遍历

VULNERABLE: Opening files using unsanitized user input
SECURE:
python
import os
ALLOWED_DIR = '/var/www/uploads'
file_name = request.args.get('file')
file_path = os.path.join(ALLOWED_DIR, file_name)
file_path = os.path.realpath(file_path)
if not file_path.startswith(os.path.realpath(ALLOWED_DIR)):
    raise ValueError("Invalid file path")
with open(file_path, 'r') as f:
    content = f.read()
VULNERABLE: Opening files using unsanitized user input
SECURE:
python
import os
ALLOWED_DIR = '/var/www/uploads'
file_name = request.args.get('file')
file_path = os.path.join(ALLOWED_DIR, file_name)
file_path = os.path.realpath(file_path)
if not file_path.startswith(os.path.realpath(ALLOWED_DIR)):
    raise ValueError("Invalid file path")
with open(file_path, 'r') as f:
    content = f.read()

Insecure Deserialization

不安全反序列化

VULNERABLE: pickle.loads(), yaml.load() with untrusted data
SECURE:
python
import json
data = json.loads(user_input)  # SECURE
import yaml
config = yaml.safe_load(user_input)  # SECURE
VULNERABLE: pickle.loads(), yaml.load() with untrusted data
SECURE:
python
import json
data = json.loads(user_input)  # SECURE
import yaml
config = yaml.safe_load(user_input)  # SECURE

Command Injection

命令注入

VULNERABLE: os.system() or subprocess with shell=True and user input
SECURE:
python
subprocess.run(['ping', '-c', '4', user_input])  # Array args
import shlex
safe_input = shlex.quote(user_input)  # Input validation
VULNERABLE: os.system() or subprocess with shell=True and user input
SECURE:
python
subprocess.run(['ping', '-c', '4', user_input])  # Array args
import shlex
safe_input = shlex.quote(user_input)  # Input validation

Insecure Random

不安全随机数

VULNERABLE: random module for security-critical operations
SECURE:
python
import secrets
token = secrets.token_hex(16)
session_id = secrets.token_urlsafe(32)
VULNERABLE: random module for security-critical operations
SECURE:
python
import secrets
token = secrets.token_hex(16)
session_id = secrets.token_urlsafe(32)

Framework Security

框架安全

Django

Django

VULNERABLE: @csrf_exempt, DEBUG=True, weak SECRET_KEY, missing security middleware
SECURE:
python
undefined
VULNERABLE: @csrf_exempt, DEBUG=True, weak SECRET_KEY, missing security middleware
SECURE:
python
undefined

settings.py

settings.py

DEBUG = False SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
SECURE_SSL_REDIRECT = True SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True X_FRAME_OPTIONS = 'DENY'
undefined
DEBUG = False SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
SECURE_SSL_REDIRECT = True SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True X_FRAME_OPTIONS = 'DENY'
undefined

Flask

Flask

VULNERABLE: debug=True, weak secret_key, CORS wildcard
SECURE:
python
import os
from flask_talisman import Talisman

app.secret_key = os.environ.get('FLASK_SECRET_KEY')
Talisman(app, force_https=True)
CORS(app, origins=['https://example.com'])
VULNERABLE: debug=True, weak secret_key, CORS wildcard
SECURE:
python
import os
from flask_talisman import Talisman

app.secret_key = os.environ.get('FLASK_SECRET_KEY')
Talisman(app, force_https=True)
CORS(app, origins=['https://example.com'])

Express.js

Express.js

VULNERABLE: Missing helmet, CORS wildcard, no rate limiting
SECURE:
javascript
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');

app.use(helmet());
app.use(cors({ origin: 'https://example.com' }));
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
VULNERABLE: Missing helmet, CORS wildcard, no rate limiting
SECURE:
javascript
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');

app.use(helmet());
app.use(cors({ origin: 'https://example.com' }));
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));

Multi-Language Scanner Implementation

多语言扫描器实现

python
import json
import subprocess
from pathlib import Path
from typing import Dict, List, Any
from dataclasses import dataclass
from datetime import datetime

@dataclass
class SASTFinding:
    tool: str
    severity: str
    category: str
    title: str
    description: str
    file_path: str
    line_number: int
    cwe: str
    owasp: str
    confidence: str

class MultiLanguageSASTScanner:
    def __init__(self, project_path: str):
        self.project_path = Path(project_path)
        self.findings: List[SASTFinding] = []

    def detect_languages(self) -> List[str]:
        """Auto-detect languages"""
        languages = []
        indicators = {
            'python': ['*.py', 'requirements.txt'],
            'javascript': ['*.js', 'package.json'],
            'typescript': ['*.ts', 'tsconfig.json'],
            'java': ['*.java', 'pom.xml'],
            'ruby': ['*.rb', 'Gemfile'],
            'go': ['*.go', 'go.mod'],
            'rust': ['*.rs', 'Cargo.toml'],
        }
        for lang, patterns in indicators.items():
            for pattern in patterns:
                if list(self.project_path.glob(f'**/{pattern}')):
                    languages.append(lang)
                    break
        return languages

    def run_comprehensive_sast(self) -> Dict[str, Any]:
        """Execute all applicable SAST tools"""
        languages = self.detect_languages()

        scan_results = {
            'timestamp': datetime.now().isoformat(),
            'languages': languages,
            'tools_executed': [],
            'findings': []
        }

        self.run_semgrep_scan()
        scan_results['tools_executed'].append('semgrep')

        if 'python' in languages:
            self.run_bandit_scan()
            scan_results['tools_executed'].append('bandit')
        if 'javascript' in languages or 'typescript' in languages:
            self.run_eslint_security_scan()
            scan_results['tools_executed'].append('eslint-security')

        scan_results['findings'] = [vars(f) for f in self.findings]
        scan_results['summary'] = self.generate_summary()
        return scan_results

    def run_semgrep_scan(self):
        """Run Semgrep"""
        for ruleset in ['auto', 'p/security-audit', 'p/owasp-top-ten']:
            try:
                result = subprocess.run([
                    'semgrep', '--config', ruleset, '--json', '--quiet',
                    str(self.project_path)
                ], capture_output=True, text=True, timeout=300)

                if result.stdout:
                    data = json.loads(result.stdout)
                    for f in data.get('results', []):
                        self.findings.append(SASTFinding(
                            tool='semgrep',
                            severity=f.get('extra', {}).get('severity', 'MEDIUM').upper(),
                            category='sast',
                            title=f.get('check_id', ''),
                            description=f.get('extra', {}).get('message', ''),
                            file_path=f.get('path', ''),
                            line_number=f.get('start', {}).get('line', 0),
                            cwe=f.get('extra', {}).get('metadata', {}).get('cwe', ''),
                            owasp=f.get('extra', {}).get('metadata', {}).get('owasp', ''),
                            confidence=f.get('extra', {}).get('metadata', {}).get('confidence', 'MEDIUM')
                        ))
            except Exception as e:
                print(f"Semgrep {ruleset} failed: {e}")

    def generate_summary(self) -> Dict[str, Any]:
        """Generate statistics"""
        severity_counts = {'CRITICAL': 0, 'HIGH': 0, 'MEDIUM': 0, 'LOW': 0}
        for f in self.findings:
            severity_counts[f.severity] = severity_counts.get(f.severity, 0) + 1

        return {
            'total_findings': len(self.findings),
            'severity_breakdown': severity_counts,
            'risk_score': self.calculate_risk_score(severity_counts)
        }

    def calculate_risk_score(self, severity_counts: Dict[str, int]) -> int:
        """Risk score 0-100"""
        weights = {'CRITICAL': 10, 'HIGH': 7, 'MEDIUM': 4, 'LOW': 1}
        total = sum(weights[s] * c for s, c in severity_counts.items())
        return min(100, int((total / 50) * 100))
python
import json
import subprocess
from pathlib import Path
from typing import Dict, List, Any
from dataclasses import dataclass
from datetime import datetime

@dataclass
class SASTFinding:
    tool: str
    severity: str
    category: str
    title: str
    description: str
    file_path: str
    line_number: int
    cwe: str
    owasp: str
    confidence: str

class MultiLanguageSASTScanner:
    def __init__(self, project_path: str):
        self.project_path = Path(project_path)
        self.findings: List[SASTFinding] = []

    def detect_languages(self) -> List[str]:
        """Auto-detect languages"""
        languages = []
        indicators = {
            'python': ['*.py', 'requirements.txt'],
            'javascript': ['*.js', 'package.json'],
            'typescript': ['*.ts', 'tsconfig.json'],
            'java': ['*.java', 'pom.xml'],
            'ruby': ['*.rb', 'Gemfile'],
            'go': ['*.go', 'go.mod'],
            'rust': ['*.rs', 'Cargo.toml'],
        }
        for lang, patterns in indicators.items():
            for pattern in patterns:
                if list(self.project_path.glob(f'**/{pattern}')):
                    languages.append(lang)
                    break
        return languages

    def run_comprehensive_sast(self) -> Dict[str, Any]:
        """Execute all applicable SAST tools"""
        languages = self.detect_languages()

        scan_results = {
            'timestamp': datetime.now().isoformat(),
            'languages': languages,
            'tools_executed': [],
            'findings': []
        }

        self.run_semgrep_scan()
        scan_results['tools_executed'].append('semgrep')

        if 'python' in languages:
            self.run_bandit_scan()
            scan_results['tools_executed'].append('bandit')
        if 'javascript' in languages or 'typescript' in languages:
            self.run_eslint_security_scan()
            scan_results['tools_executed'].append('eslint-security')

        scan_results['findings'] = [vars(f) for f in self.findings]
        scan_results['summary'] = self.generate_summary()
        return scan_results

    def run_semgrep_scan(self):
        """Run Semgrep"""
        for ruleset in ['auto', 'p/security-audit', 'p/owasp-top-ten']:
            try:
                result = subprocess.run([
                    'semgrep', '--config', ruleset, '--json', '--quiet',
                    str(self.project_path)
                ], capture_output=True, text=True, timeout=300)

                if result.stdout:
                    data = json.loads(result.stdout)
                    for f in data.get('results', []):
                        self.findings.append(SASTFinding(
                            tool='semgrep',
                            severity=f.get('extra', {}).get('severity', 'MEDIUM').upper(),
                            category='sast',
                            title=f.get('check_id', ''),
                            description=f.get('extra', {}).get('message', ''),
                            file_path=f.get('path', ''),
                            line_number=f.get('start', {}).get('line', 0),
                            cwe=f.get('extra', {}).get('metadata', {}).get('cwe', ''),
                            owasp=f.get('extra', {}).get('metadata', {}).get('owasp', ''),
                            confidence=f.get('extra', {}).get('metadata', {}).get('confidence', 'MEDIUM')
                        ))
            except Exception as e:
                print(f"Semgrep {ruleset} failed: {e}")

    def generate_summary(self) -> Dict[str, Any]:
        """Generate statistics"""
        severity_counts = {'CRITICAL': 0, 'HIGH': 0, 'MEDIUM': 0, 'LOW': 0}
        for f in self.findings:
            severity_counts[f.severity] = severity_counts.get(f.severity, 0) + 1

        return {
            'total_findings': len(self.findings),
            'severity_breakdown': severity_counts,
            'risk_score': self.calculate_risk_score(severity_counts)
        }

    def calculate_risk_score(self, severity_counts: Dict[str, int]) -> int:
        """Risk score 0-100"""
        weights = {'CRITICAL': 10, 'HIGH': 7, 'MEDIUM': 4, 'LOW': 1}
        total = sum(weights[s] * c for s, c in severity_counts.items())
        return min(100, int((total / 50) * 100))

CI/CD Integration

CI/CD集成

GitHub Actions

GitHub Actions

yaml
name: SAST Scan
on:
  pull_request:
    branches: [main]

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install tools
        run: |
          pip install bandit semgrep
          npm install -g eslint @eslint/plugin-security

      - name: Run scans
        run: |
          bandit -r . -f json -o bandit.json || true
          semgrep --config=auto --json --output=semgrep.json || true

      - name: Upload reports
        uses: actions/upload-artifact@v3
        with:
          name: sast-reports
          path: |
            bandit.json
            semgrep.json
yaml
name: SAST Scan
on:
  pull_request:
    branches: [main]

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install tools
        run: |
          pip install bandit semgrep
          npm install -g eslint @eslint/plugin-security

      - name: Run scans
        run: |
          bandit -r . -f json -o bandit.json || true
          semgrep --config=auto --json --output=semgrep.json || true

      - name: Upload reports
        uses: actions/upload-artifact@v3
        with:
          name: sast-reports
          path: |
            bandit.json
            semgrep.json

GitLab CI

GitLab CI

yaml
sast:
  stage: test
  image: python:3.11
  script:
    - pip install bandit semgrep
    - bandit -r . -f json -o bandit.json || true
    - semgrep --config=auto --json --output=semgrep.json || true
  artifacts:
    reports:
      sast: bandit.json
yaml
sast:
  stage: test
  image: python:3.11
  script:
    - pip install bandit semgrep
    - bandit -r . -f json -o bandit.json || true
    - semgrep --config=auto --json --output=semgrep.json || true
  artifacts:
    reports:
      sast: bandit.json

Best Practices

最佳实践

  1. Run early and often - Pre-commit hooks and CI/CD
  2. Combine multiple tools - Different tools catch different vulnerabilities
  3. Tune false positives - Configure exclusions and thresholds
  4. Prioritize findings - Focus on CRITICAL/HIGH first
  5. Framework-aware scanning - Use specific rulesets
  6. Custom rules - Organization-specific patterns
  7. Developer training - Secure coding practices
  8. Incremental remediation - Fix gradually
  9. Baseline management - Track known issues
  10. Regular updates - Keep tools current
  1. 尽早且频繁运行 - 预提交钩子与CI/CD流程集成
  2. 组合使用多种工具 - 不同工具可检测不同类型的漏洞
  3. 调优误报 - 配置排除项与阈值
  4. 优先处理检测结果 - 先聚焦CRITICAL/HIGH级别的漏洞
  5. 框架感知扫描 - 使用特定规则集
  6. 自定义规则 - 适配组织特定的安全模式
  7. 开发者培训 - 安全编码实践
  8. 增量修复 - 逐步修复漏洞
  9. 基线管理 - 跟踪已知问题
  10. 定期更新 - 保持工具为最新版本

Related Tools

相关工具

  • security-secrets.md - Advanced credential detection
  • security-owasp.md - OWASP Top 10 assessment
  • security-api.md - API security testing
  • security-scan.md - Comprehensive security scanning
  • security-secrets.md - 高级凭证检测
  • security-owasp.md - OWASP Top 10评估
  • security-api.md - API安全测试
  • security-scan.md - 全面安全扫描