mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-10 20:33:20 +03:00
Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills: - scripts/agent.py: 80-150 line Python agents using real libraries (impacket, boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.) - references/api-reference.md: real API documentation with method signatures - LICENSE: MIT license for all skill folders
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,52 @@
|
||||
# API Reference: Implementing API Security Testing with 42Crunch
|
||||
|
||||
## 42Crunch API Security Audit
|
||||
|
||||
```bash
|
||||
# Upload OpenAPI spec for audit
|
||||
curl -X POST https://platform.42crunch.com/api/v2/apis \
|
||||
-H "X-API-KEY: $CRUNCH_KEY" \
|
||||
-F "specfile=@openapi.yaml"
|
||||
|
||||
# Get audit report
|
||||
curl https://platform.42crunch.com/api/v2/apis/{api_id}/assessmentreport \
|
||||
-H "X-API-KEY: $CRUNCH_KEY"
|
||||
```
|
||||
|
||||
## OWASP API Security Top 10 (2023)
|
||||
|
||||
| ID | Risk | Audit Check |
|
||||
|----|------|-------------|
|
||||
| API1 | Broken Object Level Auth | BOLA path patterns |
|
||||
| API2 | Broken Authentication | Security schemes |
|
||||
| API3 | Broken Object Property Auth | Mass assignment |
|
||||
| API4 | Unrestricted Resource Consumption | Rate limits |
|
||||
| API5 | Broken Function Level Auth | Admin endpoints |
|
||||
| API8 | Security Misconfiguration | HTTP, CORS, headers |
|
||||
|
||||
## Security Score Deductions
|
||||
|
||||
| Issue | Deduction | Severity |
|
||||
|-------|-----------|----------|
|
||||
| No security schemes | -30 | CRITICAL |
|
||||
| Security disabled on endpoint | -25 | CRITICAL |
|
||||
| No global security | -20 | HIGH |
|
||||
| HTTP server URL | -15 | HIGH |
|
||||
| No input schema | -15 | HIGH |
|
||||
| Mass assignment risk | -10 | MEDIUM |
|
||||
| Unbounded string param | -5 | MEDIUM |
|
||||
|
||||
## CI/CD Integration (GitHub Actions)
|
||||
|
||||
```yaml
|
||||
- uses: 42Crunch/api-security-audit-action@v3
|
||||
with:
|
||||
api-token: ${{ secrets.CRUNCH_TOKEN }}
|
||||
min-score: 70
|
||||
```
|
||||
|
||||
### References
|
||||
|
||||
- 42Crunch Platform: https://42crunch.com/
|
||||
- OWASP API Top 10: https://owasp.org/API-Security/
|
||||
- 42Crunch GitHub Action: https://github.com/42Crunch/api-security-audit-action
|
||||
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Agent for API security testing using 42Crunch audit methodology."""
|
||||
|
||||
import json
|
||||
import argparse
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
yaml = None
|
||||
|
||||
|
||||
OWASP_API_CHECKS = {
|
||||
"API1:2023": {"name": "Broken Object Level Authorization", "check": "bola"},
|
||||
"API2:2023": {"name": "Broken Authentication", "check": "auth"},
|
||||
"API3:2023": {"name": "Broken Object Property Level Authorization", "check": "bopla"},
|
||||
"API4:2023": {"name": "Unrestricted Resource Consumption", "check": "resource"},
|
||||
"API5:2023": {"name": "Broken Function Level Authorization", "check": "bfla"},
|
||||
"API6:2023": {"name": "Unrestricted Access to Sensitive Business Flows", "check": "flow"},
|
||||
"API7:2023": {"name": "Server-Side Request Forgery", "check": "ssrf"},
|
||||
"API8:2023": {"name": "Security Misconfiguration", "check": "config"},
|
||||
"API9:2023": {"name": "Improper Inventory Management", "check": "inventory"},
|
||||
"API10:2023": {"name": "Unsafe Consumption of APIs", "check": "consumption"},
|
||||
}
|
||||
|
||||
|
||||
def load_spec(spec_path):
|
||||
"""Load OpenAPI spec."""
|
||||
with open(spec_path) as f:
|
||||
if spec_path.endswith((".yaml", ".yml")):
|
||||
return yaml.safe_load(f)
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def audit_spec_security(spec):
|
||||
"""Perform static security audit of OpenAPI specification."""
|
||||
findings = []
|
||||
security_schemes = spec.get("components", {}).get("securitySchemes", {})
|
||||
global_security = spec.get("security", [])
|
||||
if not security_schemes:
|
||||
findings.append({
|
||||
"owasp": "API2:2023", "issue": "no_security_schemes",
|
||||
"severity": "CRITICAL", "score_deduction": 30,
|
||||
})
|
||||
if not global_security:
|
||||
findings.append({
|
||||
"owasp": "API8:2023", "issue": "no_global_security",
|
||||
"severity": "HIGH", "score_deduction": 20,
|
||||
})
|
||||
paths = spec.get("paths", {})
|
||||
for path, methods in paths.items():
|
||||
for method, details in methods.items():
|
||||
if method not in ("get", "post", "put", "patch", "delete"):
|
||||
continue
|
||||
if details.get("security") == []:
|
||||
findings.append({
|
||||
"path": path, "method": method.upper(),
|
||||
"owasp": "API2:2023", "issue": "security_disabled",
|
||||
"severity": "CRITICAL", "score_deduction": 25,
|
||||
})
|
||||
if method in ("post", "put", "patch"):
|
||||
body = details.get("requestBody", {})
|
||||
content = body.get("content", {})
|
||||
for media, media_def in content.items():
|
||||
schema = media_def.get("schema", {})
|
||||
if not schema:
|
||||
findings.append({
|
||||
"path": path, "method": method.upper(),
|
||||
"owasp": "API3:2023", "issue": "no_input_schema",
|
||||
"severity": "HIGH", "score_deduction": 15,
|
||||
})
|
||||
if schema.get("additionalProperties") is not False:
|
||||
findings.append({
|
||||
"path": path, "method": method.upper(),
|
||||
"owasp": "API3:2023", "issue": "mass_assignment_risk",
|
||||
"severity": "MEDIUM", "score_deduction": 10,
|
||||
})
|
||||
for param in details.get("parameters", []):
|
||||
p_schema = param.get("schema", {})
|
||||
if p_schema.get("type") == "string" and not p_schema.get("maxLength"):
|
||||
findings.append({
|
||||
"path": path, "method": method.upper(),
|
||||
"parameter": param.get("name"),
|
||||
"owasp": "API4:2023", "issue": "unbounded_string",
|
||||
"severity": "MEDIUM", "score_deduction": 5,
|
||||
})
|
||||
responses = details.get("responses", {})
|
||||
if "429" not in responses:
|
||||
findings.append({
|
||||
"path": path, "method": method.upper(),
|
||||
"owasp": "API4:2023", "issue": "no_429_response",
|
||||
"severity": "MEDIUM", "score_deduction": 5,
|
||||
})
|
||||
servers = spec.get("servers", [])
|
||||
for server in servers:
|
||||
url = server.get("url", "")
|
||||
if url.startswith("http://"):
|
||||
findings.append({
|
||||
"server": url, "owasp": "API8:2023",
|
||||
"issue": "http_not_https", "severity": "HIGH", "score_deduction": 15,
|
||||
})
|
||||
return findings
|
||||
|
||||
|
||||
def calculate_security_score(findings):
|
||||
"""Calculate security score (0-100) based on findings."""
|
||||
total_deduction = sum(f.get("score_deduction", 0) for f in findings)
|
||||
score = max(0, 100 - total_deduction)
|
||||
if score >= 80:
|
||||
grade = "A"
|
||||
elif score >= 60:
|
||||
grade = "B"
|
||||
elif score >= 40:
|
||||
grade = "C"
|
||||
else:
|
||||
grade = "F"
|
||||
return {"score": score, "grade": grade, "total_findings": len(findings)}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="42Crunch-Style API Security Testing Agent")
|
||||
parser.add_argument("--spec", required=True, help="OpenAPI spec file")
|
||||
parser.add_argument("--output", default="api_security_test_report.json")
|
||||
args = parser.parse_args()
|
||||
|
||||
spec = load_spec(args.spec)
|
||||
report = {"generated_at": datetime.utcnow().isoformat()}
|
||||
|
||||
findings = audit_spec_security(spec)
|
||||
score = calculate_security_score(findings)
|
||||
report["security_score"] = score
|
||||
report["findings"] = findings
|
||||
report["owasp_coverage"] = {k: v["name"] for k, v in OWASP_API_CHECKS.items()}
|
||||
|
||||
print(f"[+] Security Score: {score['score']}/100 (Grade: {score['grade']})")
|
||||
print(f"[+] Findings: {len(findings)}")
|
||||
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2, default=str)
|
||||
print(f"[+] Report saved to {args.output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user