Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Static Application Security Testing (SAST) for code vulnerability analysis across multiple languages and frameworks
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 477% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 400% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 131% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 141% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 41% | 0% |
Static Application Security Testing (SAST) for comprehensive code vulnerability detection across multiple languages, frameworks, and security patterns.
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.
bash# Installation & scan pip install bandit bandit -r . -f json -o bandit-report.json bandit -r . -ll -ii -f json # High/Critical only
Configuration: .bandit
yamlexclude_dirs: ['/tests/', '/venv/', '/.tox/', '/build/'] tests: [B201, B301, B302, B303, B304, B305, B307, B308, B312, B323, B324, B501, B502, B506, B602, B608] skips: [B101]
bashnpm 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" } }
bashpip 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
yamlrules: - 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]
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
VULNERABLE: String formatting/concatenation with user input in SQL queries
SECURE:
python# Parameterized queries cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) User.objects.filter(id=user_id) # ORM
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: Hardcoded API keys, passwords, tokens in source code
SECURE:
pythonimport os API_KEY = os.environ.get('API_KEY') PASSWORD = os.getenv('DB_PASSWORD')
VULNERABLE: Opening files using unsanitized user input
SECURE:
pythonimport 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: pickle.loads(), yaml.load() with untrusted data
SECURE:
pythonimport json data = json.loads(user_input) # SECURE import yaml config = yaml.safe_load(user_input) # SECURE
VULNERABLE: os.system() or subprocess with shell=True and user input
SECURE:
pythonsubprocess.run(['ping', '-c', '4', user_input]) # Array args import shlex safe_input = shlex.quote(user_input) # Input validation
VULNERABLE: random module for security-critical operations
SECURE:
pythonimport secrets token = secrets.token_hex(16) session_id = secrets.token_urlsafe(32)
VULNERABLE: @csrf_exempt, DEBUG=True, weak SECRET_KEY, missing security middleware
SECURE:
python# 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'
VULNERABLE: debug=True, weak secret_key, CORS wildcard
SECURE:
pythonimport 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: Missing helmet, CORS wildcard, no rate limiting
SECURE:
javascriptconst 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 }));
pythonimport 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))
yamlname: 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
yamlsast: 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
Other measured skills in the registry, with their headline benchmark lift.