Files
gh-agentsecops-secopsagentkit/skills/devsecops/container-grype/references/vulnerability_remediation.md
2025-11-29 17:51:02 +08:00

511 lines
10 KiB
Markdown

# Vulnerability Remediation Patterns
Common patterns for remediating dependency vulnerabilities detected by Grype.
## Table of Contents
- [General Remediation Strategies](#general-remediation-strategies)
- [Package Update Patterns](#package-update-patterns)
- [Base Image Updates](#base-image-updates)
- [Dependency Pinning](#dependency-pinning)
- [Compensating Controls](#compensating-controls)
- [Language-Specific Patterns](#language-specific-patterns)
## General Remediation Strategies
### Strategy 1: Direct Dependency Update
**When to use**: Vulnerability in a directly declared dependency
**Pattern**:
1. Identify fixed version from Grype output
2. Update dependency version in manifest file
3. Test application compatibility
4. Re-scan to verify fix
5. Deploy updated application
**Example**:
```bash
# Grype reports: lodash@4.17.15 has CVE-2020-8203, fixed in 4.17.19
# Update package.json
npm install lodash@4.17.19
npm test
grype dir:. --only-fixed
```
### Strategy 2: Transitive Dependency Update
**When to use**: Vulnerability in an indirect dependency
**Pattern**:
1. Identify which direct dependency includes the vulnerable package
2. Check if direct dependency has an update that resolves the issue
3. Update direct dependency or use dependency override mechanism
4. Re-scan to verify fix
**Example (npm)**:
```json
// package.json - Override transitive dependency
{
"overrides": {
"lodash": "^4.17.21"
}
}
```
**Example (pip)**:
```txt
# constraints.txt
lodash>=4.17.21
```
### Strategy 3: Base Image Update
**When to use**: Vulnerability in OS packages from container base image
**Pattern**:
1. Identify vulnerable OS package and fixed version
2. Update to newer base image tag or rebuild with package updates
3. Re-scan updated image
4. Test application on new base image
**Example**:
```dockerfile
# Before: Alpine 3.14 with vulnerable openssl
FROM alpine:3.14
# After: Alpine 3.19 with fixed openssl
FROM alpine:3.19
# Or: Explicit package update
FROM alpine:3.14
RUN apk upgrade --no-cache openssl
```
### Strategy 4: Patch or Backport
**When to use**: No fixed version available or update breaks compatibility
**Pattern**:
1. Research if security patch exists separately from full version update
2. Apply patch using package manager's patching mechanism
3. Consider backporting fix if feasible
4. Document patch and establish review schedule
**Example (npm postinstall)**:
```json
{
"scripts": {
"postinstall": "patch-package"
}
}
```
### Strategy 5: Compensating Controls
**When to use**: Fix not available and risk must be accepted
**Pattern**:
1. Document vulnerability and risk acceptance
2. Implement network, application, or operational controls
3. Enhance monitoring and detection
4. Schedule regular review (quarterly)
5. Track for future remediation when fix becomes available
## Package Update Patterns
### Pattern: Semantic Versioning Updates
**Minor/Patch Updates** (Generally Safe):
```bash
# Python: Update to latest patch version
pip install --upgrade 'package>=1.2.0,<1.3.0'
# Node.js: Update to latest minor version
npm update package
# Go: Update to latest patch
go get -u=patch github.com/org/package
```
**Major Updates** (Breaking Changes):
```bash
# Review changelog before updating
npm show package versions
pip index versions package
# Update and test thoroughly
npm install package@3.0.0
npm test
```
### Pattern: Lock File Management
**Update specific package**:
```bash
# npm
npm install package@latest
npm install # Update lock file
# pip
pip install --upgrade package
pip freeze > requirements.txt
# Go
go get -u github.com/org/package
go mod tidy
```
**Update all dependencies**:
```bash
# npm (interactive)
npm-check-updates --interactive
# pip
pip list --outdated | cut -d ' ' -f1 | xargs -n1 pip install -U
# Go
go get -u ./...
go mod tidy
```
## Base Image Updates
### Pattern: Minimal Base Images
**Reduce attack surface with minimal images**:
```dockerfile
# ❌ Large attack surface
FROM ubuntu:22.04
# ✅ Minimal attack surface
FROM alpine:3.19
# or
FROM gcr.io/distroless/base-debian12
# ✅ Minimal for specific language
FROM python:3.11-slim
FROM node:20-alpine
```
**Benefits**:
- Fewer packages = fewer vulnerabilities
- Smaller image size
- Faster scans
### Pattern: Multi-Stage Builds
**Separate build dependencies from runtime**:
```dockerfile
# Build stage with full toolchain
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage with minimal image
FROM node:20-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
CMD ["node", "dist/index.js"]
```
**Benefits**:
- Build tools not present in final image
- Reduced vulnerability exposure
- Smaller production image
### Pattern: Regular Base Image Updates
**Automate base image updates**:
```yaml
# Dependabot config for Dockerfile
version: 2
updates:
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
```
**Manual update process**:
```bash
# Check for newer base image versions
docker pull alpine:3.19
docker images alpine
# Update Dockerfile
sed -i 's/FROM alpine:3.18/FROM alpine:3.19/' Dockerfile
# Rebuild and scan
docker build -t myapp:latest .
grype myapp:latest
```
## Dependency Pinning
### Pattern: Pin to Secure Versions
**Lock to known-good versions**:
```dockerfile
# ✅ Pin specific versions
FROM alpine:3.19.0@sha256:abc123...
# Install specific package versions
RUN apk add --no-cache \
ca-certificates=20240226-r0 \
openssl=3.1.4-r0
```
```json
// package.json - Exact versions
{
"dependencies": {
"express": "4.18.2",
"lodash": "4.17.21"
}
}
```
**Benefits**:
- Reproducible builds
- Controlled updates
- Prevent automatic vulnerability introduction
**Drawbacks**:
- Manual update effort
- May miss security patches
- Requires active maintenance
### Pattern: Range-Based Pinning
**Allow patch updates, lock major/minor**:
```json
// package.json - Allow patch updates
{
"dependencies": {
"express": "~4.18.2", // Allow 4.18.x
"lodash": "^4.17.21" // Allow 4.x.x
}
}
```
```python
# requirements.txt - Compatible releases
express>=4.18.2,<5.0.0
lodash>=4.17.21,<5.0.0
```
## Compensating Controls
### Pattern: Network Segmentation
**Isolate vulnerable systems**:
```yaml
# Docker Compose network isolation
services:
vulnerable-service:
image: myapp:vulnerable
networks:
- internal
# No external port exposure
gateway:
image: nginx:alpine
ports:
- "80:80"
networks:
- internal
- external
networks:
internal:
internal: true
external:
```
**Benefits**:
- Limits attack surface
- Contains potential breaches
- Buys time for proper remediation
### Pattern: Web Application Firewall (WAF)
**Block exploit attempts at perimeter**:
```nginx
# ModSecurity/OWASP Core Rule Set
location / {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
proxy_pass http://vulnerable-backend;
}
```
**Virtual Patching**:
- Create WAF rules for specific CVEs
- Block known exploit patterns
- Monitor for exploitation attempts
### Pattern: Runtime Application Self-Protection (RASP)
**Detect and prevent exploitation at runtime**:
```python
# Example: Add input validation
def process_user_input(data):
# Validate against known exploit patterns
if contains_sql_injection(data):
log_security_event("SQL injection attempt blocked")
raise SecurityException("Invalid input")
return sanitize_input(data)
```
## Language-Specific Patterns
### Python
**Update vulnerable package**:
```bash
# Check for vulnerabilities
grype dir:/path/to/project -o json
# Update package
pip install --upgrade vulnerable-package
# Freeze updated dependencies
pip freeze > requirements.txt
# Verify fix
grype dir:/path/to/project
```
**Use constraints files**:
```bash
# constraints.txt
vulnerable-package>=1.2.3 # CVE-2024-XXXX fixed
# Install with constraints
pip install -r requirements.txt -c constraints.txt
```
### Node.js
**Update vulnerable package**:
```bash
# Check for vulnerabilities
npm audit
grype dir:. -o json
# Fix automatically (if possible)
npm audit fix
# Manual update
npm install package@version
# Verify fix
npm audit
grype dir:.
```
**Override transitive dependencies**:
```json
{
"overrides": {
"vulnerable-package": "^2.0.0"
}
}
```
### Go
**Update vulnerable module**:
```bash
# Check for vulnerabilities
go list -m all | grype
# Update specific module
go get -u github.com/org/vulnerable-module
# Update all modules
go get -u ./...
# Verify and tidy
go mod tidy
grype dir:.
```
### Java/Maven
**Update vulnerable dependency**:
```xml
<!-- pom.xml - Update version -->
<dependency>
<groupId>org.example</groupId>
<artifactId>vulnerable-lib</artifactId>
<version>2.0.0</version> <!-- Updated from 1.0.0 -->
</dependency>
```
**Force dependency version**:
```xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>vulnerable-lib</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
</dependencyManagement>
```
### Rust
**Update vulnerable crate**:
```bash
# Check for vulnerabilities
cargo audit
grype dir:. -o json
# Update specific crate
cargo update -p vulnerable-crate
# Update all crates
cargo update
# Verify fix
cargo audit
grype dir:.
```
## Verification Workflow
After applying any remediation:
Progress:
[ ] 1. **Re-scan**: Run Grype scan to verify vulnerability resolved
[ ] 2. **Test**: Execute test suite to ensure no functionality broken
[ ] 3. **Document**: Record CVE, fix applied, and verification results
[ ] 4. **Deploy**: Roll out fix to affected environments
[ ] 5. **Monitor**: Watch for related security issues or regressions
Work through each step systematically. Check off completed items.
## References
- [npm Security Best Practices](https://docs.npmjs.com/security-best-practices)
- [Python Packaging Security](https://packaging.python.org/en/latest/guides/security/)
- [Go Modules Security](https://go.dev/blog/vuln)
- [OWASP Dependency Check](https://owasp.org/www-project-dependency-check/)