Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 17:51:02 +08:00
commit ff1f4bd119
252 changed files with 72682 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
# Assets Directory
Place files that will be used in the output Claude produces:
- Templates
- Configuration files
- Images/logos
- Boilerplate code
These files are NOT loaded into context but copied/modified in output.

View File

@@ -0,0 +1,357 @@
# Security-Enhanced CI/CD Pipeline Template
#
# This template demonstrates security best practices for CI/CD pipelines.
# Adapt this template to your specific security tool and workflow needs.
#
# Key Security Features:
# - SAST (Static Application Security Testing)
# - Dependency vulnerability scanning
# - Secrets detection
# - Infrastructure-as-Code security scanning
# - Container image scanning
# - Security artifact uploading for compliance
name: Security Scan Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
schedule:
# Run weekly security scans on Sunday at 2 AM UTC
- cron: '0 2 * * 0'
workflow_dispatch: # Allow manual trigger
# Security: Restrict permissions to minimum required
permissions:
contents: read
security-events: write # For uploading SARIF results
pull-requests: write # For commenting on PRs
env:
# Configuration
SECURITY_SCAN_FAIL_ON: 'critical,high' # Fail build on these severities
REPORT_DIR: 'security-reports'
jobs:
# Job 1: Static Application Security Testing (SAST)
sast-scan:
name: SAST Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for better analysis
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Run SAST Scanner
run: |
# Example: Using Semgrep for SAST
pip install semgrep
semgrep --config=auto \
--json \
--output ${{ env.REPORT_DIR }}/sast-results.json \
. || true
# Alternative: Bandit for Python projects
# pip install bandit
# bandit -r . -f json -o ${{ env.REPORT_DIR }}/bandit-results.json
- name: Process SAST Results
run: |
# Parse results and fail on critical/high severity
python3 -c "
import json
import sys
with open('${{ env.REPORT_DIR }}/sast-results.json') as f:
results = json.load(f)
critical = len([r for r in results.get('results', []) if r.get('extra', {}).get('severity') == 'ERROR'])
high = len([r for r in results.get('results', []) if r.get('extra', {}).get('severity') == 'WARNING'])
print(f'Critical findings: {critical}')
print(f'High findings: {high}')
if critical > 0:
print('❌ Build failed: Critical security issues found')
sys.exit(1)
elif high > 0:
print('⚠️ Warning: High severity issues found')
# Optionally fail on high severity
# sys.exit(1)
else:
print('✅ No critical security issues found')
"
- name: Upload SAST Results
if: always()
uses: actions/upload-artifact@v4
with:
name: sast-results
path: ${{ env.REPORT_DIR }}/sast-results.json
retention-days: 30
# Job 2: Dependency Vulnerability Scanning
dependency-scan:
name: Dependency Vulnerability Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Scan Python Dependencies
if: hashFiles('requirements.txt') != ''
run: |
pip install safety
safety check \
--json \
--output ${{ env.REPORT_DIR }}/safety-results.json \
|| true
- name: Scan Node Dependencies
if: hashFiles('package.json') != ''
run: |
npm audit --json > ${{ env.REPORT_DIR }}/npm-audit.json || true
- name: Process Dependency Results
run: |
# Check for critical vulnerabilities
if [ -f "${{ env.REPORT_DIR }}/safety-results.json" ]; then
critical_count=$(python3 -c "import json; data=json.load(open('${{ env.REPORT_DIR }}/safety-results.json')); print(len([v for v in data.get('vulnerabilities', []) if v.get('severity', '').lower() == 'critical']))")
echo "Critical vulnerabilities: $critical_count"
if [ "$critical_count" -gt "0" ]; then
echo "❌ Build failed: Critical vulnerabilities in dependencies"
exit 1
fi
fi
- name: Upload Dependency Scan Results
if: always()
uses: actions/upload-artifact@v4
with:
name: dependency-scan-results
path: ${{ env.REPORT_DIR }}/
retention-days: 30
# Job 3: Secrets Detection
secrets-scan:
name: Secrets Detection
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history to scan all commits
- name: Run Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_ENABLE_SUMMARY: true
- name: Alternative - TruffleHog Scan
if: false # Set to true to enable
run: |
pip install truffleHog
trufflehog --json --regex --entropy=True . \
> ${{ env.REPORT_DIR }}/trufflehog-results.json || true
- name: Upload Secrets Scan Results
if: always()
uses: actions/upload-artifact@v4
with:
name: secrets-scan-results
path: ${{ env.REPORT_DIR }}/
retention-days: 30
# Job 4: Container Image Scanning
container-scan:
name: Container Image Security Scan
runs-on: ubuntu-latest
if: hashFiles('Dockerfile') != ''
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker Image
run: |
docker build -t app:${{ github.sha }} .
- name: Run Trivy Scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: app:${{ github.sha }}
format: 'sarif'
output: '${{ env.REPORT_DIR }}/trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy Results to GitHub Security
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: '${{ env.REPORT_DIR }}/trivy-results.sarif'
- name: Upload Container Scan Results
if: always()
uses: actions/upload-artifact@v4
with:
name: container-scan-results
path: ${{ env.REPORT_DIR }}/
retention-days: 30
# Job 5: Infrastructure-as-Code Security Scanning
iac-scan:
name: IaC Security Scan
runs-on: ubuntu-latest
if: hashFiles('**/*.tf', '**/*.yaml', '**/*.yml') != ''
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Checkov
run: |
pip install checkov
checkov -d . \
--output json \
--output-file ${{ env.REPORT_DIR }}/checkov-results.json \
--quiet \
|| true
- name: Run tfsec (for Terraform)
if: hashFiles('**/*.tf') != ''
run: |
curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bash
tfsec . \
--format json \
--out ${{ env.REPORT_DIR }}/tfsec-results.json \
|| true
- name: Process IaC Results
run: |
# Fail on critical findings
if [ -f "${{ env.REPORT_DIR }}/checkov-results.json" ]; then
critical_count=$(python3 -c "import json; data=json.load(open('${{ env.REPORT_DIR }}/checkov-results.json')); print(data.get('summary', {}).get('failed', 0))")
echo "Failed checks: $critical_count"
if [ "$critical_count" -gt "0" ]; then
echo "⚠️ Warning: IaC security issues found"
# Optionally fail the build
# exit 1
fi
fi
- name: Upload IaC Scan Results
if: always()
uses: actions/upload-artifact@v4
with:
name: iac-scan-results
path: ${{ env.REPORT_DIR }}/
retention-days: 30
# Job 6: Security Report Generation and Notification
security-report:
name: Generate Security Report
runs-on: ubuntu-latest
needs: [sast-scan, dependency-scan, secrets-scan]
if: always()
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download All Scan Results
uses: actions/download-artifact@v4
with:
path: all-results/
- name: Generate Consolidated Report
run: |
# Consolidate all security scan results
mkdir -p consolidated-report
cat > consolidated-report/security-summary.md << 'EOF'
# Security Scan Summary
**Scan Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
**Commit**: ${{ github.sha }}
**Branch**: ${{ github.ref_name }}
## Scan Results
### SAST Scan
See artifacts: `sast-results`
### Dependency Scan
See artifacts: `dependency-scan-results`
### Secrets Scan
See artifacts: `secrets-scan-results`
### Container Scan
See artifacts: `container-scan-results`
### IaC Scan
See artifacts: `iac-scan-results`
---
For detailed results, download scan artifacts from this workflow run.
EOF
- name: Comment on PR (if applicable)
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = fs.readFileSync('consolidated-report/security-summary.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: report
});
- name: Upload Consolidated Report
if: always()
uses: actions/upload-artifact@v4
with:
name: consolidated-security-report
path: consolidated-report/
retention-days: 90
# Security Best Practices Demonstrated:
#
# 1. ✅ Minimal permissions (principle of least privilege)
# 2. ✅ Multiple security scan types (defense in depth)
# 3. ✅ Fail-fast on critical findings
# 4. ✅ Secrets detection across full git history
# 5. ✅ Container image scanning before deployment
# 6. ✅ IaC scanning for misconfigurations
# 7. ✅ Artifact retention for compliance audit trail
# 8. ✅ SARIF format for GitHub Security integration
# 9. ✅ Scheduled scans for continuous monitoring
# 10. ✅ PR comments for developer feedback
#
# Compliance Mappings:
# - SOC 2: CC6.1, CC6.6, CC7.2 (Security monitoring and logging)
# - PCI-DSS: 6.2, 6.5 (Secure development practices)
# - NIST: SA-11 (Developer Security Testing)
# - OWASP: Integrated security testing throughout SDLC

View File

@@ -0,0 +1,189 @@
# GitHub Actions Workflow for Spectral API Security Linting
# This workflow validates OpenAPI/AsyncAPI specifications against security best practices
name: API Security Linting with Spectral
on:
push:
branches: [main, develop]
paths:
- 'api-specs/**/*.yaml'
- 'api-specs/**/*.yml'
- 'api-specs/**/*.json'
- '.spectral.yaml'
pull_request:
branches: [main, develop]
paths:
- 'api-specs/**/*.yaml'
- 'api-specs/**/*.yml'
- 'api-specs/**/*.json'
- '.spectral.yaml'
jobs:
spectral-lint:
name: Lint API Specifications
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install Spectral CLI
run: npm install -g @stoplight/spectral-cli
- name: Verify Spectral Installation
run: spectral --version
- name: Lint API Specifications (GitHub Actions Format)
run: |
spectral lint api-specs/**/*.{yaml,yml,json} \
--ruleset .spectral.yaml \
--format github-actions \
--fail-severity error
continue-on-error: true
- name: Generate JSON Report
if: always()
run: |
mkdir -p reports
spectral lint api-specs/**/*.{yaml,yml,json} \
--ruleset .spectral.yaml \
--format json \
--output reports/spectral-results.json || true
- name: Generate HTML Report
if: always()
run: |
# Download parse script if not in repository
if [ ! -f "scripts/parse_spectral_results.py" ]; then
curl -o scripts/parse_spectral_results.py \
https://raw.githubusercontent.com/SecOpsAgentKit/skills/main/appsec/api-spectral/scripts/parse_spectral_results.py
chmod +x scripts/parse_spectral_results.py
fi
python3 scripts/parse_spectral_results.py \
--input reports/spectral-results.json \
--output reports/spectral-report.html \
--format html \
--map-owasp
- name: Upload Spectral Reports
if: always()
uses: actions/upload-artifact@v4
with:
name: spectral-security-reports
path: reports/
retention-days: 30
- name: Check for Critical Issues
run: |
if [ -f "reports/spectral-results.json" ]; then
CRITICAL_COUNT=$(jq '[.[] | select(.severity == 0)] | length' reports/spectral-results.json)
echo "Critical security issues found: $CRITICAL_COUNT"
if [ "$CRITICAL_COUNT" -gt 0 ]; then
echo "::error::Found $CRITICAL_COUNT critical security issues in API specifications"
exit 1
fi
fi
- name: Comment PR with Results
if: github.event_name == 'pull_request' && always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
if (fs.existsSync('reports/spectral-results.json')) {
const results = JSON.parse(fs.readFileSync('reports/spectral-results.json', 'utf8'));
const severityCounts = results.reduce((acc, finding) => {
const severity = ['error', 'warn', 'info', 'hint'][finding.severity] || 'unknown';
acc[severity] = (acc[severity] || 0) + 1;
return acc;
}, {});
const errorCount = severityCounts.error || 0;
const warnCount = severityCounts.warn || 0;
const infoCount = severityCounts.info || 0;
const summary = `## 🔒 API Security Lint Results
**Total Findings:** ${results.length}
| Severity | Count |
|----------|-------|
| 🔴 Error | ${errorCount} |
| 🟡 Warning | ${warnCount} |
| 🔵 Info | ${infoCount} |
${errorCount > 0 ? '⚠️ **Action Required:** Fix error-level security issues before merging.' : '✅ No critical security issues found.'}
📄 [View Detailed Report](../actions/runs/${context.runId})
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
});
}
# Optional: Separate job for OWASP-specific validation
owasp-validation:
name: OWASP API Security Validation
runs-on: ubuntu-latest
needs: spectral-lint
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Spectral CLI
run: npm install -g @stoplight/spectral-cli
- name: Validate Against OWASP Ruleset
run: |
# Use OWASP-specific ruleset if available
if [ -f ".spectral-owasp.yaml" ]; then
RULESET=".spectral-owasp.yaml"
else
# Download OWASP ruleset template
curl -o .spectral-owasp.yaml \
https://raw.githubusercontent.com/SecOpsAgentKit/skills/main/appsec/api-spectral/assets/spectral-owasp.yaml
RULESET=".spectral-owasp.yaml"
fi
spectral lint api-specs/**/*.{yaml,yml,json} \
--ruleset "$RULESET" \
--format stylish \
--fail-severity warn
- name: Generate OWASP Compliance Report
if: always()
run: |
mkdir -p reports
spectral lint api-specs/**/*.{yaml,yml,json} \
--ruleset .spectral-owasp.yaml \
--format json \
--output reports/owasp-validation.json || true
- name: Upload OWASP Report
if: always()
uses: actions/upload-artifact@v4
with:
name: owasp-compliance-report
path: reports/owasp-validation.json
retention-days: 30

View File

@@ -0,0 +1,355 @@
# Security Rule Template
#
# This template demonstrates how to structure security rules/policies.
# Adapt this template to your specific security tool (Semgrep, OPA, etc.)
#
# Rule Structure Best Practices:
# - Clear rule ID and metadata
# - Severity classification
# - Framework mappings (OWASP, CWE)
# - Remediation guidance
# - Example vulnerable and fixed code
rules:
# Example Rule 1: SQL Injection Detection
- id: sql-injection-string-concatenation
metadata:
name: "SQL Injection via String Concatenation"
description: "Detects potential SQL injection vulnerabilities from string concatenation in SQL queries"
severity: "HIGH"
category: "security"
subcategory: "injection"
# Security Framework Mappings
owasp:
- "A03:2021 - Injection"
cwe:
- "CWE-89: SQL Injection"
mitre_attack:
- "T1190: Exploit Public-Facing Application"
# Compliance Standards
compliance:
- "PCI-DSS 6.5.1: Injection flaws"
- "NIST 800-53 SI-10: Information Input Validation"
# Confidence and Impact
confidence: "HIGH"
likelihood: "HIGH"
impact: "HIGH"
# References
references:
- "https://owasp.org/www-community/attacks/SQL_Injection"
- "https://cwe.mitre.org/data/definitions/89.html"
- "https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html"
# Languages this rule applies to
languages:
- python
- javascript
- java
- go
# Detection Pattern (example using Semgrep-style syntax)
pattern-either:
- pattern: |
cursor.execute($SQL + $VAR)
- pattern: |
cursor.execute(f"... {$VAR} ...")
- pattern: |
cursor.execute("..." + $VAR + "...")
# What to report when found
message: |
Potential SQL injection vulnerability detected. SQL query is constructed using
string concatenation or f-strings with user input. This allows attackers to
inject malicious SQL code.
Use parameterized queries instead:
- Python: cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
- JavaScript: db.query("SELECT * FROM users WHERE id = $1", [userId])
See: https://owasp.org/www-community/attacks/SQL_Injection
# Suggested fix (auto-fix if supported)
fix: |
Use parameterized queries with placeholders
# Example vulnerable code
examples:
- vulnerable: |
# Vulnerable: String concatenation
user_id = request.GET['id']
query = "SELECT * FROM users WHERE id = " + user_id
cursor.execute(query)
- fixed: |
# Fixed: Parameterized query
user_id = request.GET['id']
query = "SELECT * FROM users WHERE id = ?"
cursor.execute(query, (user_id,))
# Example Rule 2: Hardcoded Secrets Detection
- id: hardcoded-secret-credential
metadata:
name: "Hardcoded Secret or Credential"
description: "Detects hardcoded secrets, API keys, passwords, or tokens in source code"
severity: "CRITICAL"
category: "security"
subcategory: "secrets"
owasp:
- "A07:2021 - Identification and Authentication Failures"
cwe:
- "CWE-798: Use of Hard-coded Credentials"
- "CWE-259: Use of Hard-coded Password"
compliance:
- "PCI-DSS 8.2.1: Use of strong cryptography"
- "SOC 2 CC6.1: Logical access controls"
- "GDPR Article 32: Security of processing"
confidence: "MEDIUM"
likelihood: "HIGH"
impact: "CRITICAL"
references:
- "https://cwe.mitre.org/data/definitions/798.html"
- "https://owasp.org/www-community/vulnerabilities/Use_of_hard-coded_password"
languages:
- python
- javascript
- java
- go
- ruby
pattern-either:
- pattern: |
password = "..."
- pattern: |
api_key = "..."
- pattern: |
secret = "..."
- pattern: |
token = "..."
pattern-not: |
$VAR = ""
message: |
Potential hardcoded secret detected. Hardcoding credentials in source code
is a critical security vulnerability that can lead to unauthorized access
if the code is exposed.
Use environment variables or a secrets management system instead:
- Python: os.environ.get('API_KEY')
- Node.js: process.env.API_KEY
- Secrets Manager: AWS Secrets Manager, HashiCorp Vault, etc.
See: https://cwe.mitre.org/data/definitions/798.html
examples:
- vulnerable: |
# Vulnerable: Hardcoded API key
api_key = "sk-1234567890abcdef"
api.authenticate(api_key)
- fixed: |
# Fixed: Environment variable
import os
api_key = os.environ.get('API_KEY')
if not api_key:
raise ValueError("API_KEY environment variable not set")
api.authenticate(api_key)
# Example Rule 3: XSS via Unsafe HTML Rendering
- id: xss-unsafe-html-rendering
metadata:
name: "Cross-Site Scripting (XSS) via Unsafe HTML"
description: "Detects unsafe HTML rendering that could lead to XSS vulnerabilities"
severity: "HIGH"
category: "security"
subcategory: "xss"
owasp:
- "A03:2021 - Injection"
cwe:
- "CWE-79: Cross-site Scripting (XSS)"
- "CWE-80: Improper Neutralization of Script-Related HTML Tags"
compliance:
- "PCI-DSS 6.5.7: Cross-site scripting"
- "NIST 800-53 SI-10: Information Input Validation"
confidence: "HIGH"
likelihood: "MEDIUM"
impact: "HIGH"
references:
- "https://owasp.org/www-community/attacks/xss/"
- "https://cwe.mitre.org/data/definitions/79.html"
- "https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html"
languages:
- javascript
- typescript
- jsx
- tsx
pattern-either:
- pattern: |
dangerouslySetInnerHTML={{__html: $VAR}}
- pattern: |
innerHTML = $VAR
message: |
Potential XSS vulnerability detected. Setting HTML content directly from
user input without sanitization can allow attackers to inject malicious
JavaScript code.
Use one of these safe alternatives:
- React: Use {userInput} for automatic escaping
- DOMPurify: const clean = DOMPurify.sanitize(dirty);
- Framework-specific sanitizers
See: https://owasp.org/www-community/attacks/xss/
examples:
- vulnerable: |
// Vulnerable: Unsanitized HTML
function UserComment({ comment }) {
return <div dangerouslySetInnerHTML={{__html: comment}} />;
}
- fixed: |
// Fixed: Sanitized with DOMPurify
import DOMPurify from 'dompurify';
function UserComment({ comment }) {
const sanitized = DOMPurify.sanitize(comment);
return <div dangerouslySetInnerHTML={{__html: sanitized}} />;
}
# Example Rule 4: Insecure Cryptography
- id: weak-cryptographic-algorithm
metadata:
name: "Weak Cryptographic Algorithm"
description: "Detects use of weak or deprecated cryptographic algorithms"
severity: "HIGH"
category: "security"
subcategory: "cryptography"
owasp:
- "A02:2021 - Cryptographic Failures"
cwe:
- "CWE-327: Use of a Broken or Risky Cryptographic Algorithm"
- "CWE-326: Inadequate Encryption Strength"
compliance:
- "PCI-DSS 4.1: Use strong cryptography"
- "NIST 800-53 SC-13: Cryptographic Protection"
- "GDPR Article 32: Security of processing"
confidence: "HIGH"
likelihood: "MEDIUM"
impact: "HIGH"
references:
- "https://cwe.mitre.org/data/definitions/327.html"
- "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/09-Testing_for_Weak_Cryptography/"
languages:
- python
- javascript
- java
pattern-either:
- pattern: |
hashlib.md5(...)
- pattern: |
hashlib.sha1(...)
- pattern: |
crypto.createHash('md5')
- pattern: |
crypto.createHash('sha1')
message: |
Weak cryptographic algorithm detected (MD5 or SHA1). These algorithms are
considered cryptographically broken and should not be used for security purposes.
Use strong alternatives:
- For hashing: SHA-256, SHA-384, or SHA-512
- For password hashing: bcrypt, argon2, or PBKDF2
- Python: hashlib.sha256()
- Node.js: crypto.createHash('sha256')
See: https://cwe.mitre.org/data/definitions/327.html
examples:
- vulnerable: |
# Vulnerable: MD5 hash
import hashlib
hash_value = hashlib.md5(data).hexdigest()
- fixed: |
# Fixed: SHA-256 hash
import hashlib
hash_value = hashlib.sha256(data).hexdigest()
# Rule Configuration
configuration:
# Global settings
enabled: true
severity_threshold: "MEDIUM" # Report findings at MEDIUM severity and above
# Performance tuning
max_file_size_kb: 1024
exclude_patterns:
- "test/*"
- "tests/*"
- "node_modules/*"
- "vendor/*"
- "*.min.js"
# False positive reduction
confidence_threshold: "MEDIUM" # Only report findings with MEDIUM confidence or higher
# Rule Metadata Schema
# This section documents the expected structure for rules
metadata_schema:
required:
- id: "Unique identifier for the rule (kebab-case)"
- name: "Human-readable rule name"
- description: "What the rule detects"
- severity: "CRITICAL | HIGH | MEDIUM | LOW | INFO"
- category: "security | best-practice | performance"
optional:
- subcategory: "Specific type (injection, xss, secrets, etc.)"
- owasp: "OWASP Top 10 mappings"
- cwe: "CWE identifier(s)"
- mitre_attack: "MITRE ATT&CK technique(s)"
- compliance: "Compliance standard references"
- confidence: "Detection confidence level"
- likelihood: "Likelihood of exploitation"
- impact: "Potential impact if exploited"
- references: "External documentation links"
# Usage Instructions:
#
# 1. Copy this template when creating new security rules
# 2. Update metadata fields with appropriate framework mappings
# 3. Customize detection patterns for your tool (Semgrep, OPA, etc.)
# 4. Provide clear remediation guidance in the message field
# 5. Include both vulnerable and fixed code examples
# 6. Test rules on real codebases before deployment
#
# Best Practices:
# - Map to multiple frameworks (OWASP, CWE, MITRE ATT&CK)
# - Include compliance standard references
# - Provide actionable remediation guidance
# - Show code examples (vulnerable vs. fixed)
# - Tune confidence levels to reduce false positives
# - Exclude test directories to reduce noise

View File

@@ -0,0 +1,293 @@
# Comprehensive OWASP API Security Top 10 2023 Spectral Ruleset
# This ruleset enforces OWASP API Security best practices for OpenAPI specifications
extends: ["spectral:oas"]
rules:
# ============================================================================
# API1:2023 - Broken Object Level Authorization
# ============================================================================
operation-security-defined:
description: All operations must have security requirements defined (OWASP API1)
severity: error
given: $.paths[*][get,post,put,patch,delete,head]
then:
- field: security
function: truthy
message: "Operations must define security requirements to prevent unauthorized object access (OWASP API1:2023 - Broken Object Level Authorization)"
id-parameters-require-security:
description: Operations with ID parameters must have security defined
severity: error
given: $.paths[?(@property =~ /(\/\{id\}|\/\{.*[_-]id\})/i)][get,put,patch,delete]
then:
- field: security
function: truthy
message: "Operations with ID parameters require security to prevent IDOR vulnerabilities (OWASP API1:2023)"
# ============================================================================
# API2:2023 - Broken Authentication
# ============================================================================
security-schemes-required:
description: API must define security schemes (OWASP API2)
severity: error
given: $.components
then:
- field: securitySchemes
function: truthy
message: "API must define security schemes to prevent authentication bypass (OWASP API2:2023 - Broken Authentication)"
no-http-basic-auth:
description: HTTP Basic authentication is insecure for APIs
severity: error
given: $.components.securitySchemes[*]
then:
- field: scheme
function: pattern
functionOptions:
notMatch: "^basic$"
message: "HTTP Basic authentication transmits credentials in plain text - use OAuth2, API key, or JWT (OWASP API2:2023)"
bearer-format-specified:
description: Bearer authentication should specify token format (JWT recommended)
severity: warn
given: $.components.securitySchemes[?(@.type == 'http' && @.scheme == 'bearer')]
then:
- field: bearerFormat
function: truthy
message: "Bearer authentication should specify token format (bearerFormat: JWT) for clarity (OWASP API2:2023)"
# ============================================================================
# API3:2023 - Broken Object Property Level Authorization
# ============================================================================
no-additional-properties:
description: Prevent mass assignment by disabling additionalProperties
severity: warn
given: $.components.schemas[?(@.type == 'object')]
then:
- field: additionalProperties
function: falsy
message: "Set additionalProperties to false to prevent mass assignment vulnerabilities (OWASP API3:2023 - Broken Object Property Level Authorization)"
schemas-have-properties:
description: Object schemas should explicitly define properties
severity: warn
given: $.components.schemas[?(@.type == 'object')]
then:
- field: properties
function: truthy
message: "Explicitly define object properties to control data exposure (OWASP API3:2023)"
# ============================================================================
# API4:2023 - Unrestricted Resource Consumption
# ============================================================================
rate-limit-headers-documented:
description: API should document rate limiting headers
severity: warn
given: $.paths[*][get,post,put,patch,delete].responses[?(@property < '300')].headers
then:
function: schema
functionOptions:
schema:
type: object
anyOf:
- required: [X-RateLimit-Limit]
- required: [X-Rate-Limit-Limit]
- required: [RateLimit-Limit]
message: "Document rate limiting headers to communicate resource consumption limits (OWASP API4:2023 - Unrestricted Resource Consumption)"
pagination-parameters-present:
description: List operations should support pagination
severity: warn
given: $.paths[*].get
then:
- field: parameters
function: schema
functionOptions:
schema:
type: array
contains:
anyOf:
- properties:
name:
enum: [limit, per_page, page_size]
- properties:
name:
enum: [offset, page, cursor]
message: "List operations should support pagination (limit/offset or cursor) to prevent resource exhaustion (OWASP API4:2023)"
# ============================================================================
# API5:2023 - Broken Function Level Authorization
# ============================================================================
write-operations-require-security:
description: Write operations must have security requirements
severity: error
given: $.paths[*][post,put,patch,delete]
then:
- field: security
function: truthy
message: "Write operations must have security requirements to prevent unauthorized function access (OWASP API5:2023 - Broken Function Level Authorization)"
admin-paths-require-security:
description: Admin endpoints must have strict security
severity: error
given: $.paths[?(@property =~ /admin/i)][*]
then:
- field: security
function: truthy
message: "Admin endpoints require security requirements with appropriate scopes (OWASP API5:2023)"
# ============================================================================
# API7:2023 - Server Side Request Forgery
# ============================================================================
no-url-parameters:
description: Avoid URL parameters to prevent SSRF attacks
severity: warn
given: $.paths[*][*].parameters[?(@.in == 'query' || @.in == 'body')][?(@.name =~ /(url|uri|link|callback|redirect|webhook)/i)]
then:
function: truthy
message: "URL parameters can enable SSRF attacks - validate and whitelist destination URLs (OWASP API7:2023 - Server Side Request Forgery)"
# ============================================================================
# API8:2023 - Security Misconfiguration
# ============================================================================
servers-use-https:
description: All API servers must use HTTPS
severity: error
given: $.servers[*].url
then:
function: pattern
functionOptions:
match: "^https://"
message: "Server URLs must use HTTPS protocol for secure communication (OWASP API8:2023 - Security Misconfiguration)"
no-example-servers:
description: Replace example server URLs with actual endpoints
severity: error
given: $.servers[*].url
then:
function: pattern
functionOptions:
notMatch: "example\\.com"
message: "Replace example.com with actual production server URLs (OWASP API8:2023)"
security-headers-in-responses:
description: Document security headers in responses
severity: info
given: $.paths[*][*].responses[*].headers
then:
function: schema
functionOptions:
schema:
type: object
anyOf:
- required: [X-Content-Type-Options]
- required: [X-Frame-Options]
- required: [Strict-Transport-Security]
- required: [Content-Security-Policy]
message: "Consider documenting security headers (X-Content-Type-Options, X-Frame-Options, HSTS, CSP) (OWASP API8:2023)"
# ============================================================================
# API9:2023 - Improper Inventory Management
# ============================================================================
api-version-required:
description: API specification must include version
severity: error
given: $.info
then:
- field: version
function: truthy
message: "API version must be specified for proper inventory management (OWASP API9:2023 - Improper Inventory Management)"
semantic-versioning-format:
description: Use semantic versioning for API versions
severity: warn
given: $.info.version
then:
function: pattern
functionOptions:
match: "^\\d+\\.\\d+(\\.\\d+)?$"
message: "Use semantic versioning format (MAJOR.MINOR.PATCH) for API versions (OWASP API9:2023)"
contact-info-required:
description: API must include contact information
severity: warn
given: $.info
then:
- field: contact
function: truthy
message: "Include contact information for API support and security reporting (OWASP API9:2023)"
deprecated-endpoints-documented:
description: Deprecated endpoints must document migration path
severity: warn
given: $.paths[*][*][?(@.deprecated == true)]
then:
- field: description
function: pattern
functionOptions:
match: "(deprecate|migrate|alternative|replacement|use instead)"
message: "Deprecated endpoints must document migration path and timeline (OWASP API9:2023)"
# ============================================================================
# API10:2023 - Unsafe Consumption of APIs
# ============================================================================
validate-external-api-responses:
description: Document validation of external API responses
severity: info
given: $.paths[*][*].responses[*].content[*].schema
then:
- field: description
function: truthy
message: "Document schema validation for all API responses, especially from external APIs (OWASP API10:2023 - Unsafe Consumption of APIs)"
# ============================================================================
# Additional Security Best Practices
# ============================================================================
no-pii-in-query-parameters:
description: Prevent PII exposure in URL query parameters
severity: error
given: $.paths[*][*].parameters[?(@.in == 'query')].name
then:
function: pattern
functionOptions:
notMatch: "(?i)(ssn|social.?security|credit.?card|password|secret|token|api.?key|private|passport|driver.?license)"
message: "Query parameters must not contain PII or sensitive data - use request body with HTTPS instead"
consistent-error-response-format:
description: Error responses should follow consistent format
severity: warn
given: $.paths[*][*].responses[?(@property >= '400')].content.application/json.schema
then:
function: schema
functionOptions:
schema:
type: object
required: [error, message]
message: "Error responses should follow consistent format with 'error' and 'message' fields"
no-verbose-error-details:
description: 5xx errors should not expose internal details
severity: warn
given: $.paths[*][*].responses[?(@property >= '500')].content[*].schema.properties
then:
function: schema
functionOptions:
schema:
type: object
not:
anyOf:
- required: [stack_trace]
- required: [stackTrace]
- required: [debug_info]
message: "5xx error responses should not expose stack traces or internal details in production"