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:

  1. Code Vulnerabilities - Static analysis with Bandit

  2. 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

  1. Check fixed version:

    # Update dependency
    uv add requests@2.31.0
    
  2. Test thoroughly after update:

    structum test --cov
    
  3. Re-audit to confirm fix:

    structum security audit
    
  4. No fix available?

    • Evaluate risk vs. functionality

    • Consider alternative packages

    • Document decision in SECURITY.md

    • Monitor 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 scan passes

  • [ ] All HIGH severity issues resolved

  • [ ] MEDIUM severity reviewed and addressed

  • [ ] # nosec comments documented

Before Release

  • [ ] structum security audit passes

  • [ ] 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 integration

  • SECURITY.md - Vulnerability reporting process

  • docs/governance/LICENSING.md - License compliance