Add supply-chain, deserialization, cryptography, error-handling patterns
Now covers all OWASP Top 10:2025 categories: - A03: supply-chain.md (SolarWinds, Bybit, npm worm examples) - A04: cryptography.md (algorithm recommendations, key management) - A08: deserialization.md (pickle, yaml, language-specific risks) - A10: error-handling.md (fail closed, error messages)
This commit is contained in:
+126
@@ -0,0 +1,126 @@
|
||||
# Supply Chain Security
|
||||
|
||||
## Rule
|
||||
|
||||
Verify integrity of all dependencies. Generate SBOMs. Monitor for vulnerabilities.
|
||||
|
||||
**Source:** [OWASP Top 10 2025 - A03 Software Supply Chain Failures](https://owasp.org/Top10/2025/A03_2025-Software_Supply_Chain_Failures/)
|
||||
|
||||
## Attack Examples
|
||||
|
||||
- **SolarWinds (2019)**: Compromised build system, 18,000 orgs affected
|
||||
- **Bybit (2025)**: Supply chain attack in wallet software, $1.5B theft
|
||||
- **Shai-Hulud (2025)**: Self-propagating npm worm, 500+ packages
|
||||
|
||||
## Correct Pattern
|
||||
|
||||
```python
|
||||
# Generate and maintain SBOM
|
||||
import subprocess
|
||||
import json
|
||||
import hashlib
|
||||
|
||||
def generate_sbom(project_path: str) -> dict:
|
||||
"""Generate Software Bill of Materials."""
|
||||
# Use CycloneDX or SPDX format
|
||||
result = subprocess.run(
|
||||
["cyclonedx-py", "poetry", "-o", "sbom.json"],
|
||||
cwd=project_path,
|
||||
capture_output=True
|
||||
)
|
||||
with open(f"{project_path}/sbom.json") as f:
|
||||
return json.load(f)
|
||||
|
||||
# Verify package integrity
|
||||
def verify_package(package_path: str, expected_hash: str) -> bool:
|
||||
"""Verify package hash before installation."""
|
||||
with open(package_path, "rb") as f:
|
||||
actual_hash = hashlib.sha256(f.read()).hexdigest()
|
||||
return actual_hash == expected_hash
|
||||
|
||||
# Pin dependencies with hashes
|
||||
# requirements.txt with hashes:
|
||||
# requests==2.28.0 --hash=sha256:abc123...
|
||||
|
||||
# Lock file example (poetry.lock, package-lock.json)
|
||||
def verify_lockfile_integrity(lockfile_path: str) -> bool:
|
||||
"""Ensure lockfile hasn't been tampered with."""
|
||||
# Compare against known-good version in version control
|
||||
...
|
||||
```
|
||||
|
||||
## Incorrect Pattern
|
||||
|
||||
```python
|
||||
# Wrong: no version pinning
|
||||
# requirements.txt
|
||||
# requests
|
||||
# flask
|
||||
|
||||
# Wrong: pulling from arbitrary sources
|
||||
pip install https://sketchy-site.com/package.tar.gz
|
||||
|
||||
# Wrong: no integrity verification
|
||||
def install_dependency(name):
|
||||
os.system(f"pip install {name}") # No hash check
|
||||
|
||||
# Wrong: auto-updating without verification
|
||||
def auto_update():
|
||||
os.system("pip install --upgrade -r requirements.txt")
|
||||
```
|
||||
|
||||
## Dependency Scanning
|
||||
|
||||
```python
|
||||
# Integrate vulnerability scanning in CI
|
||||
def scan_dependencies() -> list[dict]:
|
||||
"""Scan for known vulnerabilities."""
|
||||
# Use tools like:
|
||||
# - OWASP Dependency-Check
|
||||
# - Snyk
|
||||
# - GitHub Dependabot
|
||||
# - OSV (Open Source Vulnerabilities)
|
||||
|
||||
result = subprocess.run(
|
||||
["pip-audit", "--format=json"],
|
||||
capture_output=True
|
||||
)
|
||||
return json.loads(result.stdout)
|
||||
|
||||
def block_on_critical(vulnerabilities: list[dict]) -> bool:
|
||||
"""Fail CI on critical vulnerabilities."""
|
||||
critical = [v for v in vulnerabilities if v["severity"] == "CRITICAL"]
|
||||
if critical:
|
||||
raise SecurityError(f"Critical vulnerabilities found: {critical}")
|
||||
return True
|
||||
```
|
||||
|
||||
## CI/CD Hardening
|
||||
|
||||
```python
|
||||
# Verify CI/CD pipeline integrity
|
||||
PIPELINE_REQUIREMENTS = {
|
||||
"mfa_required": True,
|
||||
"branch_protection": True,
|
||||
"signed_commits": True,
|
||||
"code_review_required": True,
|
||||
"secrets_scanning": True,
|
||||
}
|
||||
|
||||
def audit_pipeline(config: dict) -> list[str]:
|
||||
"""Audit CI/CD configuration."""
|
||||
issues = []
|
||||
for requirement, expected in PIPELINE_REQUIREMENTS.items():
|
||||
if config.get(requirement) != expected:
|
||||
issues.append(f"Missing: {requirement}")
|
||||
return issues
|
||||
```
|
||||
|
||||
## Edge Cases
|
||||
|
||||
- Transitive dependencies (deps of deps) can be vulnerable
|
||||
- Typosquatting attacks (similar package names)
|
||||
- Dependency confusion (internal vs public package names)
|
||||
- Compromised maintainer accounts
|
||||
- Post-install scripts can execute arbitrary code
|
||||
- IDE extensions and dev tools are part of supply chain
|
||||
Reference in New Issue
Block a user