Security Scanning Best Practices¶
Comprehensive guide to security vulnerability detection and remediation in Structum projects.
Overview¶
Security scanning is a critical component of maintainable, production-ready code. The Structum CLI Tools plugin provides automated vulnerability detection for:
Code Vulnerabilities - Static analysis with Bandit
Dependency Vulnerabilities - CVE database checking with Safety
Quick Start¶
# Install tools
pip install structum-cli-tools
# Quick scan
structum security scan
# Full audit (recommended)
structum security audit
# Generate report for CI/CD
structum security report --output security.json
Understanding Bandit¶
What Bandit Checks¶
SQL Injection (B608):
# ❌ Vulnerable
query = f"SELECT * FROM users WHERE id = {user_id}"
cursor.execute(query)
# ✅ Safe
query = "SELECT * FROM users WHERE id = %s"
cursor.execute(query, (user_id,))
Hardcoded Secrets (B105, B106):
# ❌ Vulnerable
PASSWORD = "admin123" # Hardcoded
API_KEY = "sk-1234567890"
# ✅ Safe
from os import getenv
PASSWORD = getenv("DB_PASSWORD")
API_KEY = getenv("API_KEY")
Insecure eval/exec (B307, B102):
# ❌ Dangerous
user_code = request.form["code"]
eval(user_code) # Arbitrary code execution!
# ✅ Safe alternative
import ast
tree = ast.parse(user_code, mode='eval')
# Validate tree before execution
Weak Cryptography (B304, B303):
# ❌ Weak
import md5 # Deprecated, insecure
hash = md5.new(data).hexdigest()
# ✅ Strong
from hashlib import sha256
hash = sha256(data).hexdigest()
Shell Injection (B602, B603):
# ❌ Vulnerable
import os
filename = request.form["file"]
os.system(f"cat {filename}") # Command injection!
# ✅ Safe
import subprocess
subprocess.run(["cat", filename], check=True)
Severity Levels¶
HIGH Severity¶
Impact: Direct security vulnerability
Action: Fix immediately
Examples: SQL injection, hardcoded passwords, shell injection
MEDIUM Severity¶
Impact: Potential security issue
Action: Review and fix if applicable
Examples: Weak hashing, assert in production, pickle usage
LOW Severity¶
Impact: Best practice violation
Action: Fix when convenient
Examples: HTTP instead of HTTPS, weak permissions
False Positives¶
When Bandit incorrectly flags safe code, use # nosec comment:
# Example: Assert in test file (acceptable)
def test_user_authentication():
user = authenticate("admin", "password")
assert user is not None # nosec B101 - Test code only
# Example: Known-safe eval usage
import ast
def safe_literal_eval(s: str):
return ast.literal_eval(s) # nosec B307 - ast.literal_eval is safe
IMPORTANT: Only use # nosec after thorough security review. Document why it’s safe.
Dependency Vulnerabilities (Safety)¶
Understanding CVEs¶
CVE (Common Vulnerabilities and Exposures) - Standardized vulnerability identifiers.
Example Safety output:
-> Package: requests==2.25.1
CVE: CVE-2023-32681
Severity: MEDIUM
Fixed in: 2.31.0
Description: Certificate verification bypass
Remediation Steps¶
Check fixed version:
# Update dependency uv add requests@2.31.0Test thoroughly after update:
structum test --covRe-audit to confirm fix:
structum security auditNo fix available?
Evaluate risk vs. functionality
Consider alternative packages
Document decision in
SECURITY.mdMonitor for updates
CI/CD Integration¶
GitHub Actions Workflow¶
Create .github/workflows/security.yml:
name: Security Scan
on:
push:
branches: [main]
pull_request:
# Weekly scheduled scan
schedule:
- cron: '0 0 * * 0'
jobs:
security-scan:
runs-on: ubuntu-latest
permissions:
security-events: write # For GitHub Security tab
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install tools
run: pip install structum-cli-tools
- name: Run security audit
run: structum security audit
- name: Generate JSON report
if: always()
run: structum security report -o security-report.json
- name: Upload report artifact
if: always()
uses: actions/upload-artifact@v3
with:
name: security-report
path: security-report.json
retention-days: 30
- name: Fail on HIGH severity
if: failure()
run: |
echo "::error::Security vulnerabilities detected"
exit 1
GitLab CI Example¶
security_scan:
stage: test
image: python:3.11
script:
- pip install structum-cli-tools
- structum security audit
- structum security report -o security-report.json
artifacts:
when: always
paths:
- security-report.json
reports:
junit: security-report.json
only:
- merge_requests
- main
Pre-commit Hooks¶
Catch vulnerabilities before commit:
.pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: security-scan
name: Security vulnerability scan
entry: structum security scan
language: system
pass_filenames: false
always_run: true
Install:
pip install pre-commit
pre-commit install
Security Checklist¶
Before Commit¶
[ ] No hardcoded secrets
[ ] No
eval()/exec()on user input[ ] SQL queries use parameterization
[ ] Shell commands use array format
[ ] Strong cryptography (SHA-256+, not MD5/SHA-1)
Before Pull Request¶
[ ]
structum security scanpasses[ ] All HIGH severity issues resolved
[ ] MEDIUM severity reviewed and addressed
[ ]
# noseccomments documented
Before Release¶
[ ]
structum security auditpasses[ ] All dependencies updated
[ ] No known CVEs in dependencies
[ ] Security report generated and archived
Advanced Topics¶
Custom Bandit Configuration¶
Create .bandit or pyproject.toml:
[tool.bandit]
exclude_dirs = ["/tests", "/demo"]
tests = ["B201", "B301"] # Only specific tests
skips = ["B101"] # Skip assert warnings
[tool.bandit.assert_used]
skips = ["*/test_*.py", "*/tests/*"]
Integrating with SAST Tools¶
Combine with other tools for comprehensive analysis:
# Bandit (Structum CLI Tools)
structum security scan
# Semgrep (pattern-based analysis)
semgrep --config=auto .
# Snyk (SaaS platform)
snyk test
Resources¶
Official Documentation¶
Vulnerability Databases¶
Learning Resources¶
See Also¶
:doc:
/cli/security- Security command reference:doc:
/cli/testing- Testing integrationSECURITY.md- Vulnerability reporting processdocs/governance/LICENSING.md- License compliance