<!-- AUTO-GENERATED by export-plugins.py — DO NOT EDIT -->
---
name: cwe-sans-top25
description: CWE/SANS Top 25 Most Dangerous Software Weaknesses -- classification, prevention patterns, and SAST integration for secure development
tags: [cwe, security]
---

# CWE/SANS Top 25 Most Dangerous Software Weaknesses

## Overview

The CWE/SANS Top 25 is a curated list of the most prevalent and dangerous software weaknesses maintained by MITRE. Unlike OWASP (which focuses on web/API risks), CWE classifies root-cause weaknesses in software -- memory corruption, injection flaws, improper validation -- that lead to exploitable vulnerabilities. Each weakness has a unique CWE identifier used across CVE databases, SAST tools, and compliance frameworks.

This skill organizes the Top 25 by category, provides language-specific applicability, and maps each weakness to concrete prevention patterns and SAST rules. It is designed for developers performing code reviews, security engineers configuring static analysis, and architects establishing secure coding standards.

## When to Use This Skill

- Performing security-focused code reviews on PRs
- Configuring SAST tools (Semgrep, CodeQL, Bandit) for a project
- Triaging CVEs and mapping them to root-cause weaknesses
- Building secure coding guidelines for a development team
- Evaluating third-party libraries for known weakness patterns
- Preparing for security audits or compliance reviews (SOC 2, ISO 27001)

## How It Works

### Step 1: Identify the Weakness Class

Determine which CWE category the suspected issue belongs to. Use the categories below to narrow down from broad symptoms (e.g., "crash on malformed input") to a specific CWE ID.

### Step 2: Check CVSS and EPSS Scores

For known CVEs related to the weakness, look up:
- **CVSS** (Common Vulnerability Scoring System) -- severity score (0-10)
- **EPSS** (Exploit Prediction Scoring System) -- probability of exploitation in the wild (0-1)

```bash
# Query NIST NVD for a specific CVE
curl -s "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2024-XXXXX" | \
  jq '.vulnerabilities[0].cve.metrics'
```

### Step 3: Apply the Mitigation Pattern

Each CWE has a specific mitigation pattern. Apply the pattern from the relevant category below. Mitigations should be implemented at the earliest possible phase (design > implementation > testing).

### Step 4: Verify with SAST Tools

Run static analysis to confirm the fix and prevent regression:

```bash
# Semgrep scan for Python security issues
semgrep scan --config p/python-security --config p/owasp-top-ten \
  --severity ERROR --error ./src/

# Bandit scan for Python-specific weaknesses
bandit -r ./src/ -ll -ii --format json -o bandit-report.json

# CodeQL analysis (GitHub Actions)
# Configured in .github/workflows/codeql.yml
```

### Step 5: Add to Regression Tests

Write tests that specifically exercise the weakness vector to prevent reintroduction:

```python
# Example: regression test for SQL injection (CWE-89)
import pytest

class TestSQLInjectionPrevention:
    """Regression tests ensuring parameterized queries are used."""

    @pytest.mark.parametrize("malicious_input", [
        "'; DROP TABLE users; --",
        "1 OR 1=1",
        "1 UNION SELECT * FROM credentials",
    ])
    async def test_user_lookup_rejects_injection(self, client, malicious_input):
        response = await client.get(f"/api/v1/users?search={malicious_input}")
        assert response.status_code in (200, 400)  # Must not cause 500
        # Verify no data leak from other tables
        data = response.json()
        assert "credentials" not in str(data).lower()
```

---

## Weakness Categories and Key CWEs

### Category 1: Memory Safety

These weaknesses affect languages without automatic memory management (C, C++, Rust unsafe blocks). They are the leading cause of critical remote code execution (RCE) vulnerabilities.

| CWE | Name | CVSS Range | Languages |
|-----|------|------------|-----------|
| CWE-787 | Out-of-Bounds Write | 8.0-10.0 | C, C++ |
| CWE-125 | Out-of-Bounds Read | 5.0-8.0 | C, C++ |
| CWE-416 | Use After Free | 8.0-10.0 | C, C++ |
| CWE-476 | NULL Pointer Dereference | 4.0-7.0 | C, C++, Java |
| CWE-190 | Integer Overflow | 5.0-9.0 | C, C++, Java |

**Prevention Pattern:** Use memory-safe languages (Python, Rust, Go) where possible. For C/C++, enable compiler sanitizers (`-fsanitize=address,undefined`), use smart pointers, and enforce bounds checking.

### Category 2: Injection

Injection weaknesses occur when untrusted data is sent to an interpreter as part of a command or query. They affect all languages that interface with databases, shells, or rendering engines.

| CWE | Name | CVSS Range | Languages |
|-----|------|------------|-----------|
| CWE-89 | SQL Injection | 7.0-10.0 | All (DB-connected) |
| CWE-79 | Cross-Site Scripting (XSS) | 4.0-8.0 | JavaScript, HTML |
| CWE-78 | OS Command Injection | 8.0-10.0 | All |
| CWE-94 | Code Injection | 8.0-10.0 | Python, PHP, JS |
| CWE-77 | Command Injection | 8.0-10.0 | All |

**Prevention Pattern:** Use parameterized queries (SQL), context-aware output encoding (XSS), and avoid shell=True in subprocess calls. Never construct commands by string concatenation with user input.

### Category 3: Authentication and Session Management

| CWE | Name | CVSS Range | Languages |
|-----|------|------------|-----------|
| CWE-287 | Improper Authentication | 7.0-10.0 | All |
| CWE-798 | Hard-Coded Credentials | 7.0-9.0 | All |
| CWE-306 | Missing Authentication for Critical Function | 7.0-10.0 | All |
| CWE-522 | Insufficiently Protected Credentials | 5.0-8.0 | All |

**Prevention Pattern:** Use established authentication frameworks, never hard-code secrets, enforce MFA on sensitive operations, and store credentials in secret managers (not config files or environment variables in source).

### Category 4: Authorization and Access Control

| CWE | Name | CVSS Range | Languages |
|-----|------|------------|-----------|
| CWE-862 | Missing Authorization | 7.0-9.0 | All |
| CWE-863 | Incorrect Authorization | 6.0-9.0 | All |
| CWE-269 | Improper Privilege Management | 7.0-9.0 | All |

**Prevention Pattern:** Implement default-deny authorization, check ownership on every resource access (see @owasp-api-top10 API1), enforce least-privilege, and use framework-level middleware rather than per-handler checks.

### Category 5: Cryptography

| CWE | Name | CVSS Range | Languages |
|-----|------|------------|-----------|
| CWE-327 | Broken or Risky Crypto Algorithm | 5.0-8.0 | All |
| CWE-330 | Insufficient Randomness | 4.0-7.0 | All |
| CWE-916 | Weak Password Hashing | 5.0-8.0 | All |

**Prevention Pattern:** Use modern algorithms (AES-256-GCM, SHA-256+, Ed25519), OS-provided CSPRNG (`secrets` module in Python, not `random`), and bcrypt/argon2 for password hashing. Never implement custom cryptography.

### Category 6: Input Validation and Resource Management

| CWE | Name | CVSS Range | Languages |
|-----|------|------------|-----------|
| CWE-20 | Improper Input Validation | 4.0-9.0 | All |
| CWE-22 | Path Traversal | 5.0-9.0 | All |
| CWE-352 | Cross-Site Request Forgery (CSRF) | 4.0-8.0 | Web frameworks |
| CWE-434 | Unrestricted File Upload | 7.0-10.0 | All (file handling) |
| CWE-611 | XXE (XML External Entity) | 5.0-9.0 | Java, Python, PHP |

**Prevention Pattern:** Validate all input against strict schemas (type, length, format, range). Use allow-lists over deny-lists. Canonicalize file paths before access. Disable XML external entity processing by default.

---

## Examples

### Example 1: Preventing CWE-89 (SQL Injection) with Parameterized Queries

```python
from sqlalchemy import select, text
from sqlalchemy.ext.asyncio import AsyncSession


# BAD: String concatenation -- vulnerable to CWE-89
async def search_users_insecure(db: AsyncSession, search_term: str):
    query = text(f"SELECT * FROM users WHERE name LIKE '%{search_term}%'")
    result = await db.execute(query)
    return result.all()


# GOOD: Parameterized query -- immune to CWE-89
async def search_users_secure(db: AsyncSession, search_term: str):
    query = text("SELECT * FROM users WHERE name LIKE :search")
    result = await db.execute(query, {"search": f"%{search_term}%"})
    return result.all()


# BEST: Use SQLAlchemy ORM -- parameterization is automatic
async def search_users_orm(db: AsyncSession, search_term: str):
    stmt = select(User).where(User.name.ilike(f"%{search_term}%"))
    result = await db.execute(stmt)
    return result.scalars().all()
```

### Example 2: Preventing CWE-22 (Path Traversal) with Input Validation

```python
import os
from pathlib import Path
from fastapi import APIRouter, HTTPException, status

router = APIRouter()

UPLOAD_DIR = Path("/app/uploads")


# BAD: No path validation -- vulnerable to CWE-22
@router.get("/files/{filename}")
async def get_file_insecure(filename: str):
    file_path = UPLOAD_DIR / filename  # filename could be "../../etc/passwd"
    return file_path.read_text()


# GOOD: Path canonicalization and containment check
@router.get("/files/{filename}")
async def get_file_secure(filename: str):
    # Reject obvious traversal attempts
    if ".." in filename or filename.startswith("/"):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid filename",
        )

    # Resolve to absolute path and verify containment
    file_path = (UPLOAD_DIR / filename).resolve()

    if not file_path.is_relative_to(UPLOAD_DIR.resolve()):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Access denied",
        )

    if not file_path.is_file():
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)

    return file_path.read_text()
```

### Example 3: SAST Rule for Detecting CWE-79 (XSS) with Semgrep

```yaml
# .semgrep/rules/cwe-79-xss.yaml
rules:
  - id: cwe-79-jinja2-autoescape-disabled
    patterns:
      - pattern: jinja2.Environment(..., autoescape=False, ...)
    message: >
      Jinja2 autoescape is disabled (CWE-79). This allows cross-site scripting
      when rendering user-controlled data. Set autoescape=True or use
      select_autoescape().
    severity: ERROR
    metadata:
      cwe:
        - "CWE-79: Improper Neutralization of Input During Web Page Generation"
      confidence: HIGH
      category: security
    languages: [python]

  - id: cwe-79-markupsafe-bypass
    patterns:
      - pattern: markupsafe.Markup($USER_INPUT)
    message: >
      Wrapping user input in Markup() bypasses HTML escaping (CWE-79).
      Only use Markup() for trusted, pre-sanitized content.
    severity: WARNING
    metadata:
      cwe:
        - "CWE-79: Improper Neutralization of Input During Web Page Generation"
      confidence: MEDIUM
      category: security
    languages: [python]

  - id: cwe-79-fastapi-html-response
    patterns:
      - pattern: |
          from fastapi.responses import HTMLResponse
          ...
          HTMLResponse(content=<... $USER_INPUT ...>)
    message: >
      User input rendered directly in HTMLResponse without escaping (CWE-79).
      Use a template engine with autoescape or html.escape().
    severity: ERROR
    metadata:
      cwe:
        - "CWE-79: Improper Neutralization of Input During Web Page Generation"
      confidence: MEDIUM
      category: security
    languages: [python]
```

```bash
# Run the custom rule alongside built-in rules
semgrep scan --config .semgrep/rules/ --config p/python-security \
  --severity ERROR --error ./src/
```

## Best Practices

### Do This

- Use memory-safe languages (Python, Rust, Go) to eliminate entire weakness categories (CWE-787, CWE-125, CWE-416)
- Parameterize all database queries -- use ORM query builders instead of raw SQL strings
- Canonicalize file paths with `Path.resolve()` and verify containment before access
- Use `secrets` module (not `random`) for any security-sensitive random values
- Configure SAST tools (Semgrep, Bandit) in CI/CD to block PRs introducing known weakness patterns
- Write regression tests that exercise known attack vectors for each fixed weakness
- Use allow-lists for input validation -- define what is valid rather than what is invalid
- Disable XML external entity processing by default in all XML parsers
- Hash passwords with bcrypt or argon2id, never with MD5 or SHA-1 alone

### Don't Do This

- Do not concatenate user input into SQL, shell commands, or HTML templates
- Do not use `subprocess.run(..., shell=True)` with user-controllable arguments
- Do not store secrets in source code, environment variables checked into repos, or config files
- Do not use `random` module for tokens, passwords, or cryptographic keys
- Do not disable autoescape in Jinja2 or mark user input as safe/trusted
- Do not trust file extensions for upload validation -- check content type and magic bytes
- Do not suppress SAST findings without documented justification and security review
- Do not implement custom cryptographic algorithms or protocols

## Security Checklist

### Memory Safety (CWE-787, CWE-125, CWE-416, CWE-476)
- [ ] C/C++ code compiled with `-fsanitize=address,undefined` in CI
- [ ] Smart pointers used instead of raw pointers where applicable
- [ ] Bounds-checked array access in all performance-critical loops
- [ ] Null pointer checks before all dereferences of external data

### Injection (CWE-89, CWE-79, CWE-78, CWE-94)
- [ ] All SQL queries use parameterized statements or ORM query builders
- [ ] HTML templates use auto-escaping (Jinja2 autoescape=True)
- [ ] Subprocess calls use argument lists (never `shell=True` with user input)
- [ ] No `eval()`, `exec()`, or dynamic code execution with untrusted input

### Authentication and Credentials (CWE-287, CWE-798, CWE-522)
- [ ] No hard-coded credentials in source code (scanned by SAST and git-secrets)
- [ ] Secrets stored in dedicated secret managers (GCP Secret Manager, Vault)
- [ ] Password hashing uses bcrypt or argon2id with appropriate work factors
- [ ] Authentication bypass paths audited (default credentials, magic tokens removed)

### Authorization (CWE-862, CWE-863, CWE-269)
- [ ] Default-deny authorization policy on all API endpoints
- [ ] Resource ownership verified on every object access (BOLA prevention)
- [ ] Privilege escalation paths audited (role assignment, admin functions)
- [ ] Least-privilege principle applied to service accounts and IAM roles

### Input Validation and File Handling (CWE-20, CWE-22, CWE-434, CWE-611)
- [ ] All user input validated against strict schemas (type, length, format)
- [ ] File paths canonicalized and checked for containment within allowed directories
- [ ] File uploads validated by content type, magic bytes, and size limits
- [ ] XML parsers configured to disable external entity processing
- [ ] CSRF tokens required on all state-changing endpoints

### Cryptography (CWE-327, CWE-330, CWE-916)
- [ ] Only modern crypto algorithms in use (AES-256-GCM, SHA-256+, Ed25519/X25519)
- [ ] `secrets` module used for all security-sensitive random generation
- [ ] TLS 1.2+ enforced for all network communication
- [ ] No custom or hand-rolled cryptographic implementations

## Related Skills

- @owasp-top10 -- Web application security risks with broader scope than CWE
- @owasp-api-top10 -- API-specific security risks mapped to CWE root causes
- @api-security-patterns -- Implementation patterns for securing FastAPI/Python backends

## Additional Resources

- [CWE Top 25 (2023 Edition)](https://cwe.mitre.org/top25/archive/2023/2023_top25_list.html)
- [MITRE CWE Database](https://cwe.mitre.org/)
- [Semgrep Rule Registry](https://semgrep.dev/explore)
- [NIST NVD (National Vulnerability Database)](https://nvd.nist.gov/)
- [EPSS (Exploit Prediction Scoring System)](https://www.first.org/epss/)
- [OWASP Secure Coding Practices Quick Reference](https://owasp.org/www-project-secure-coding-practices-quick-reference-guide/)

<!-- Source: .faos/custom/skills/security/cwe-sans-top25/SKILL.md -->
