Update CyberForge ML models and deployment artifacts
Browse files- README.md +4 -0
- agent_config.json +26 -0
- anomaly_detection/metadata.json +14 -0
- anomaly_detection/model.pkl +3 -0
- anomaly_detection/package_info.json +23 -0
- anomaly_detection/scaler.pkl +3 -0
- cyberforge_agent.py +60 -0
- inference.py +158 -0
- malware_detection/metadata.json +18 -0
- malware_detection/model.pkl +3 -0
- malware_detection/package_info.json +23 -0
- malware_detection/scaler.pkl +3 -0
- manifest.json +98 -0
- ml_client.js +77 -0
- phishing_detection/metadata.json +39 -0
- phishing_detection/model.pkl +3 -0
- phishing_detection/package_info.json +23 -0
- phishing_detection/scaler.pkl +3 -0
- web_attack_detection/metadata.json +35 -0
- web_attack_detection/model.pkl +3 -0
- web_attack_detection/package_info.json +23 -0
- web_attack_detection/scaler.pkl +3 -0
README.md
CHANGED
|
@@ -19,6 +19,10 @@ Production-ready machine learning models for cybersecurity threat detection.
|
|
| 19 |
|
| 20 |
| Model | Task | Accuracy | F1 Score | Inference Time |
|
| 21 |
|-------|------|----------|----------|----------------|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
|
| 24 |
## Usage
|
|
|
|
| 19 |
|
| 20 |
| Model | Task | Accuracy | F1 Score | Inference Time |
|
| 21 |
|-------|------|----------|----------|----------------|
|
| 22 |
+
| phishing_detection | random_forest | 0.9890 | 0.9890 | 0.01ms |
|
| 23 |
+
| malware_detection | gradient_boosting | 0.9985 | 0.9985 | 0.00ms |
|
| 24 |
+
| anomaly_detection | random_forest | 0.9990 | 0.9990 | 0.01ms |
|
| 25 |
+
| web_attack_detection | random_forest | 1.0000 | 1.0000 | 0.03ms |
|
| 26 |
|
| 27 |
|
| 28 |
## Usage
|
agent_config.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": "1.0.0",
|
| 3 |
+
"confidence_threshold": 0.7,
|
| 4 |
+
"max_concurrent_tasks": 5,
|
| 5 |
+
"severity_weights": {
|
| 6 |
+
"critical": 1.0,
|
| 7 |
+
"high": 0.8,
|
| 8 |
+
"medium": 0.5,
|
| 9 |
+
"low": 0.3,
|
| 10 |
+
"info": 0.1
|
| 11 |
+
},
|
| 12 |
+
"evidence_weights": {
|
| 13 |
+
"model_prediction": 0.4,
|
| 14 |
+
"signature_match": 0.3,
|
| 15 |
+
"behavioral_pattern": 0.2,
|
| 16 |
+
"heuristic_rule": 0.1
|
| 17 |
+
},
|
| 18 |
+
"task_priorities": {
|
| 19 |
+
"CRITICAL": 4,
|
| 20 |
+
"HIGH": 3,
|
| 21 |
+
"MEDIUM": 2,
|
| 22 |
+
"LOW": 1,
|
| 23 |
+
"BACKGROUND": 0
|
| 24 |
+
},
|
| 25 |
+
"gemini_model": "gemini-2.5-flash"
|
| 26 |
+
}
|
anomaly_detection/metadata.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_type": "random_forest",
|
| 3 |
+
"dataset": "anomaly_detection",
|
| 4 |
+
"accuracy": 0.999,
|
| 5 |
+
"f1_score": 0.9989986620975891,
|
| 6 |
+
"inference_time_ms": 0.006589841842651367,
|
| 7 |
+
"feature_names": [
|
| 8 |
+
"timestamp",
|
| 9 |
+
"event_id",
|
| 10 |
+
"anomaly_score"
|
| 11 |
+
],
|
| 12 |
+
"version": "1.0.0",
|
| 13 |
+
"framework": "sklearn"
|
| 14 |
+
}
|
anomaly_detection/model.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d10d6bc1da4a579239ea1485d858b1f6e16331aa5ac8c18391328629d39d75df
|
| 3 |
+
size 513929
|
anomaly_detection/package_info.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "anomaly_detection",
|
| 3 |
+
"type": "random_forest",
|
| 4 |
+
"version": "1.0.0",
|
| 5 |
+
"accuracy": 0.999,
|
| 6 |
+
"f1_score": 0.9989986620975891,
|
| 7 |
+
"inference_time_ms": 0.006589841842651367,
|
| 8 |
+
"files": {
|
| 9 |
+
"model": {
|
| 10 |
+
"path": "anomaly_detection/model.pkl",
|
| 11 |
+
"checksum": "833a0b8d0d785bdc4ab163b2f2e4a7b9",
|
| 12 |
+
"size_bytes": 513929
|
| 13 |
+
},
|
| 14 |
+
"scaler": {
|
| 15 |
+
"path": "anomaly_detection/scaler.pkl",
|
| 16 |
+
"checksum": "50935889b0c4b5813f2691c7f63bfa4a"
|
| 17 |
+
},
|
| 18 |
+
"metadata": {
|
| 19 |
+
"path": "anomaly_detection/metadata.json"
|
| 20 |
+
}
|
| 21 |
+
},
|
| 22 |
+
"packaged_at": "2026-02-15 19:21:08"
|
| 23 |
+
}
|
anomaly_detection/scaler.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6261b8dfcb46bc291d7aab75733a27ac820d7fba4a902f188f8a01bc8d6b59c3
|
| 3 |
+
size 927
|
cyberforge_agent.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
"""CyberForge Agent Intelligence Module"""
|
| 3 |
+
|
| 4 |
+
import json
|
| 5 |
+
import time
|
| 6 |
+
import numpy as np
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
from dataclasses import dataclass, asdict
|
| 9 |
+
from typing import Dict, List, Any, Optional
|
| 10 |
+
|
| 11 |
+
@dataclass
|
| 12 |
+
class AgentDecision:
|
| 13 |
+
action: str
|
| 14 |
+
confidence: float
|
| 15 |
+
reasoning: str
|
| 16 |
+
evidence: List[str]
|
| 17 |
+
risk_level: str
|
| 18 |
+
recommended_follow_up: List[str]
|
| 19 |
+
|
| 20 |
+
def to_dict(self):
|
| 21 |
+
return asdict(self)
|
| 22 |
+
|
| 23 |
+
class DecisionEngine:
|
| 24 |
+
SEVERITY_WEIGHTS = {"critical": 1.0, "high": 0.8, "medium": 0.5, "low": 0.3, "info": 0.1}
|
| 25 |
+
|
| 26 |
+
def calculate_threat_score(self, indicators: List[Dict]) -> tuple:
|
| 27 |
+
if not indicators:
|
| 28 |
+
return 0.0, "low"
|
| 29 |
+
scores = [i.get("confidence", 0.5) * self.SEVERITY_WEIGHTS.get(i.get("severity", "low"), 0.3)
|
| 30 |
+
for i in indicators]
|
| 31 |
+
score = sum(scores) / len(scores) if scores else 0
|
| 32 |
+
risk = "critical" if score >= 0.8 else "high" if score >= 0.6 else "medium" if score >= 0.4 else "low"
|
| 33 |
+
return score, risk
|
| 34 |
+
|
| 35 |
+
class CyberForgeAgent:
|
| 36 |
+
def __init__(self):
|
| 37 |
+
self.engine = DecisionEngine()
|
| 38 |
+
|
| 39 |
+
def analyze(self, url: str, data: Dict) -> Dict:
|
| 40 |
+
indicators = self._extract_indicators(data)
|
| 41 |
+
score, risk = self.engine.calculate_threat_score(indicators)
|
| 42 |
+
action = "block" if score >= 0.8 else "alert" if score >= 0.6 else "monitor" if score >= 0.4 else "allow"
|
| 43 |
+
|
| 44 |
+
return AgentDecision(
|
| 45 |
+
action=action,
|
| 46 |
+
confidence=score,
|
| 47 |
+
reasoning=f"Threat score: {score:.2f}. {len(indicators)} indicators found.",
|
| 48 |
+
evidence=[str(i) for i in indicators[:3]],
|
| 49 |
+
risk_level=risk,
|
| 50 |
+
recommended_follow_up=["Continue monitoring"]
|
| 51 |
+
).to_dict()
|
| 52 |
+
|
| 53 |
+
def _extract_indicators(self, data: Dict) -> List[Dict]:
|
| 54 |
+
indicators = []
|
| 55 |
+
sec = data.get("security_report", {})
|
| 56 |
+
if not sec.get("is_https", True):
|
| 57 |
+
indicators.append({"type": "insecure", "severity": "medium", "confidence": 0.9})
|
| 58 |
+
if sec.get("mixed_content"):
|
| 59 |
+
indicators.append({"type": "mixed_content", "severity": "medium", "confidence": 0.85})
|
| 60 |
+
return indicators
|
inference.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
"""
|
| 3 |
+
CyberForge ML Inference Module
|
| 4 |
+
Backend integration for mlService.js
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import json
|
| 8 |
+
import time
|
| 9 |
+
import joblib
|
| 10 |
+
import numpy as np
|
| 11 |
+
from pathlib import Path
|
| 12 |
+
from typing import Dict, List, Any, Optional
|
| 13 |
+
|
| 14 |
+
class CyberForgeInference:
|
| 15 |
+
"""
|
| 16 |
+
ML inference service for CyberForge backend.
|
| 17 |
+
Compatible with mlService.js API contract.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
def __init__(self, models_dir: str):
|
| 21 |
+
self.models_dir = Path(models_dir)
|
| 22 |
+
self.loaded_models = {}
|
| 23 |
+
self.manifest = self._load_manifest()
|
| 24 |
+
|
| 25 |
+
def _load_manifest(self) -> Dict:
|
| 26 |
+
manifest_path = self.models_dir / "manifest.json"
|
| 27 |
+
if manifest_path.exists():
|
| 28 |
+
with open(manifest_path) as f:
|
| 29 |
+
return json.load(f)
|
| 30 |
+
return {"models": {}}
|
| 31 |
+
|
| 32 |
+
def load_model(self, model_name: str) -> bool:
|
| 33 |
+
"""Load a model into memory"""
|
| 34 |
+
if model_name in self.loaded_models:
|
| 35 |
+
return True
|
| 36 |
+
|
| 37 |
+
model_dir = self.models_dir / model_name
|
| 38 |
+
model_path = model_dir / "model.pkl"
|
| 39 |
+
scaler_path = model_dir / "scaler.pkl"
|
| 40 |
+
|
| 41 |
+
if not model_path.exists():
|
| 42 |
+
return False
|
| 43 |
+
|
| 44 |
+
self.loaded_models[model_name] = {
|
| 45 |
+
"model": joblib.load(model_path),
|
| 46 |
+
"scaler": joblib.load(scaler_path) if scaler_path.exists() else None
|
| 47 |
+
}
|
| 48 |
+
return True
|
| 49 |
+
|
| 50 |
+
def predict(self, model_name: str, features: Dict) -> Dict:
|
| 51 |
+
"""
|
| 52 |
+
Make a prediction.
|
| 53 |
+
|
| 54 |
+
Args:
|
| 55 |
+
model_name: Name of the model to use
|
| 56 |
+
features: Feature dictionary
|
| 57 |
+
|
| 58 |
+
Returns:
|
| 59 |
+
Response matching mlService.js contract
|
| 60 |
+
"""
|
| 61 |
+
if not self.load_model(model_name):
|
| 62 |
+
return {"error": f"Model not found: {model_name}"}
|
| 63 |
+
|
| 64 |
+
model_data = self.loaded_models[model_name]
|
| 65 |
+
model = model_data["model"]
|
| 66 |
+
scaler = model_data["scaler"]
|
| 67 |
+
|
| 68 |
+
# Convert features to array
|
| 69 |
+
X = np.array([list(features.values())])
|
| 70 |
+
|
| 71 |
+
# Scale if scaler available
|
| 72 |
+
if scaler:
|
| 73 |
+
X = scaler.transform(X)
|
| 74 |
+
|
| 75 |
+
# Predict
|
| 76 |
+
start_time = time.time()
|
| 77 |
+
prediction = int(model.predict(X)[0])
|
| 78 |
+
inference_time = (time.time() - start_time) * 1000
|
| 79 |
+
|
| 80 |
+
# Get confidence
|
| 81 |
+
confidence = 0.5
|
| 82 |
+
if hasattr(model, "predict_proba"):
|
| 83 |
+
proba = model.predict_proba(X)[0]
|
| 84 |
+
confidence = float(max(proba))
|
| 85 |
+
|
| 86 |
+
# Determine risk level
|
| 87 |
+
risk_level = (
|
| 88 |
+
"critical" if confidence >= 0.9 else
|
| 89 |
+
"high" if confidence >= 0.7 else
|
| 90 |
+
"medium" if confidence >= 0.5 else
|
| 91 |
+
"low" if confidence >= 0.3 else "info"
|
| 92 |
+
)
|
| 93 |
+
|
| 94 |
+
return {
|
| 95 |
+
"prediction": prediction,
|
| 96 |
+
"confidence": confidence,
|
| 97 |
+
"risk_level": risk_level,
|
| 98 |
+
"model_name": model_name,
|
| 99 |
+
"model_version": "1.0.0",
|
| 100 |
+
"inference_time_ms": inference_time
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
def batch_predict(self, model_name: str, features_list: List[Dict]) -> List[Dict]:
|
| 104 |
+
"""Batch predictions"""
|
| 105 |
+
return [self.predict(model_name, f) for f in features_list]
|
| 106 |
+
|
| 107 |
+
def list_models(self) -> List[str]:
|
| 108 |
+
"""List available models"""
|
| 109 |
+
return list(self.manifest.get("models", {}).keys())
|
| 110 |
+
|
| 111 |
+
def get_model_info(self, model_name: str) -> Dict:
|
| 112 |
+
"""Get model information"""
|
| 113 |
+
return self.manifest.get("models", {}).get(model_name, {})
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
# FastAPI integration
|
| 117 |
+
def create_api(models_dir: str):
|
| 118 |
+
"""Create FastAPI app for model serving"""
|
| 119 |
+
try:
|
| 120 |
+
from fastapi import FastAPI, HTTPException
|
| 121 |
+
from pydantic import BaseModel
|
| 122 |
+
except ImportError:
|
| 123 |
+
return None
|
| 124 |
+
|
| 125 |
+
app = FastAPI(title="CyberForge ML API", version="1.0.0")
|
| 126 |
+
inference = CyberForgeInference(models_dir)
|
| 127 |
+
|
| 128 |
+
class PredictRequest(BaseModel):
|
| 129 |
+
model_name: str
|
| 130 |
+
features: Dict
|
| 131 |
+
|
| 132 |
+
@app.post("/predict")
|
| 133 |
+
async def predict(request: PredictRequest):
|
| 134 |
+
result = inference.predict(request.model_name, request.features)
|
| 135 |
+
if "error" in result:
|
| 136 |
+
raise HTTPException(status_code=404, detail=result["error"])
|
| 137 |
+
return result
|
| 138 |
+
|
| 139 |
+
@app.get("/models")
|
| 140 |
+
async def list_models():
|
| 141 |
+
return {"models": inference.list_models()}
|
| 142 |
+
|
| 143 |
+
@app.get("/models/{model_name}")
|
| 144 |
+
async def get_model_info(model_name: str):
|
| 145 |
+
info = inference.get_model_info(model_name)
|
| 146 |
+
if not info:
|
| 147 |
+
raise HTTPException(status_code=404, detail="Model not found")
|
| 148 |
+
return info
|
| 149 |
+
|
| 150 |
+
return app
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
if __name__ == "__main__":
|
| 154 |
+
import sys
|
| 155 |
+
models_dir = sys.argv[1] if len(sys.argv) > 1 else "."
|
| 156 |
+
|
| 157 |
+
inference = CyberForgeInference(models_dir)
|
| 158 |
+
print(f"Available models: {inference.list_models()}")
|
malware_detection/metadata.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_type": "gradient_boosting",
|
| 3 |
+
"dataset": "malware_detection",
|
| 4 |
+
"accuracy": 0.9985,
|
| 5 |
+
"f1_score": 0.9984999996249999,
|
| 6 |
+
"inference_time_ms": 0.0010334253311157227,
|
| 7 |
+
"feature_names": [
|
| 8 |
+
"file_size",
|
| 9 |
+
"entropy",
|
| 10 |
+
"pe_sections",
|
| 11 |
+
"imports",
|
| 12 |
+
"exports",
|
| 13 |
+
"strings_count",
|
| 14 |
+
"is_malware"
|
| 15 |
+
],
|
| 16 |
+
"version": "1.0.0",
|
| 17 |
+
"framework": "sklearn"
|
| 18 |
+
}
|
malware_detection/model.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0d359447aa4278fd0f36e2892e0da1a685b10e1f970a907af9a6d4cee1a7302e
|
| 3 |
+
size 205132
|
malware_detection/package_info.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "malware_detection",
|
| 3 |
+
"type": "gradient_boosting",
|
| 4 |
+
"version": "1.0.0",
|
| 5 |
+
"accuracy": 0.9985,
|
| 6 |
+
"f1_score": 0.9984999996249999,
|
| 7 |
+
"inference_time_ms": 0.0010334253311157227,
|
| 8 |
+
"files": {
|
| 9 |
+
"model": {
|
| 10 |
+
"path": "malware_detection/model.pkl",
|
| 11 |
+
"checksum": "18493b189c1d2817b561f38a1d4059d3",
|
| 12 |
+
"size_bytes": 205132
|
| 13 |
+
},
|
| 14 |
+
"scaler": {
|
| 15 |
+
"path": "malware_detection/scaler.pkl",
|
| 16 |
+
"checksum": "33d7907d3981c8e0e0e786fb87c6c6d8"
|
| 17 |
+
},
|
| 18 |
+
"metadata": {
|
| 19 |
+
"path": "malware_detection/metadata.json"
|
| 20 |
+
}
|
| 21 |
+
},
|
| 22 |
+
"packaged_at": "2026-02-15 19:21:08"
|
| 23 |
+
}
|
malware_detection/scaler.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3ba7986970aeedffad94bf1d6860f694a6b9ee08e3f49dbdfa297d2578a75053
|
| 3 |
+
size 1071
|
manifest.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"models": {
|
| 3 |
+
"phishing_detection": {
|
| 4 |
+
"name": "phishing_detection",
|
| 5 |
+
"type": "random_forest",
|
| 6 |
+
"version": "1.0.0",
|
| 7 |
+
"accuracy": 0.9889857732905002,
|
| 8 |
+
"f1_score": 0.9889844643474395,
|
| 9 |
+
"inference_time_ms": 0.010500483799549678,
|
| 10 |
+
"files": {
|
| 11 |
+
"model": {
|
| 12 |
+
"path": "phishing_detection/model.pkl",
|
| 13 |
+
"checksum": "d71ee133bc3d72d097e8ae6c84733fb2",
|
| 14 |
+
"size_bytes": 5135049
|
| 15 |
+
},
|
| 16 |
+
"scaler": {
|
| 17 |
+
"path": "phishing_detection/scaler.pkl",
|
| 18 |
+
"checksum": "8dbf6376b3219801d6995268c7d5d05a"
|
| 19 |
+
},
|
| 20 |
+
"metadata": {
|
| 21 |
+
"path": "phishing_detection/metadata.json"
|
| 22 |
+
}
|
| 23 |
+
},
|
| 24 |
+
"packaged_at": "2026-02-15 19:21:08"
|
| 25 |
+
},
|
| 26 |
+
"malware_detection": {
|
| 27 |
+
"name": "malware_detection",
|
| 28 |
+
"type": "gradient_boosting",
|
| 29 |
+
"version": "1.0.0",
|
| 30 |
+
"accuracy": 0.9985,
|
| 31 |
+
"f1_score": 0.9984999996249999,
|
| 32 |
+
"inference_time_ms": 0.0010334253311157227,
|
| 33 |
+
"files": {
|
| 34 |
+
"model": {
|
| 35 |
+
"path": "malware_detection/model.pkl",
|
| 36 |
+
"checksum": "18493b189c1d2817b561f38a1d4059d3",
|
| 37 |
+
"size_bytes": 205132
|
| 38 |
+
},
|
| 39 |
+
"scaler": {
|
| 40 |
+
"path": "malware_detection/scaler.pkl",
|
| 41 |
+
"checksum": "33d7907d3981c8e0e0e786fb87c6c6d8"
|
| 42 |
+
},
|
| 43 |
+
"metadata": {
|
| 44 |
+
"path": "malware_detection/metadata.json"
|
| 45 |
+
}
|
| 46 |
+
},
|
| 47 |
+
"packaged_at": "2026-02-15 19:21:08"
|
| 48 |
+
},
|
| 49 |
+
"anomaly_detection": {
|
| 50 |
+
"name": "anomaly_detection",
|
| 51 |
+
"type": "random_forest",
|
| 52 |
+
"version": "1.0.0",
|
| 53 |
+
"accuracy": 0.999,
|
| 54 |
+
"f1_score": 0.9989986620975891,
|
| 55 |
+
"inference_time_ms": 0.006589841842651367,
|
| 56 |
+
"files": {
|
| 57 |
+
"model": {
|
| 58 |
+
"path": "anomaly_detection/model.pkl",
|
| 59 |
+
"checksum": "833a0b8d0d785bdc4ab163b2f2e4a7b9",
|
| 60 |
+
"size_bytes": 513929
|
| 61 |
+
},
|
| 62 |
+
"scaler": {
|
| 63 |
+
"path": "anomaly_detection/scaler.pkl",
|
| 64 |
+
"checksum": "50935889b0c4b5813f2691c7f63bfa4a"
|
| 65 |
+
},
|
| 66 |
+
"metadata": {
|
| 67 |
+
"path": "anomaly_detection/metadata.json"
|
| 68 |
+
}
|
| 69 |
+
},
|
| 70 |
+
"packaged_at": "2026-02-15 19:21:08"
|
| 71 |
+
},
|
| 72 |
+
"web_attack_detection": {
|
| 73 |
+
"name": "web_attack_detection",
|
| 74 |
+
"type": "random_forest",
|
| 75 |
+
"version": "1.0.0",
|
| 76 |
+
"accuracy": 1.0,
|
| 77 |
+
"f1_score": 1.0,
|
| 78 |
+
"inference_time_ms": 0.02898440998830613,
|
| 79 |
+
"files": {
|
| 80 |
+
"model": {
|
| 81 |
+
"path": "web_attack_detection/model.pkl",
|
| 82 |
+
"checksum": "3071f634875fa3a54b389667634b1afe",
|
| 83 |
+
"size_bytes": 285769
|
| 84 |
+
},
|
| 85 |
+
"scaler": {
|
| 86 |
+
"path": "web_attack_detection/scaler.pkl",
|
| 87 |
+
"checksum": "a511f6f966d0e45f2515732533dec192"
|
| 88 |
+
},
|
| 89 |
+
"metadata": {
|
| 90 |
+
"path": "web_attack_detection/metadata.json"
|
| 91 |
+
}
|
| 92 |
+
},
|
| 93 |
+
"packaged_at": "2026-02-15 19:21:08"
|
| 94 |
+
}
|
| 95 |
+
},
|
| 96 |
+
"version": "1.0.0",
|
| 97 |
+
"created_at": "2026-02-15 19:21:08"
|
| 98 |
+
}
|
ml_client.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
/**
|
| 3 |
+
* CyberForge ML Client
|
| 4 |
+
* Integration with mlService.js
|
| 5 |
+
*/
|
| 6 |
+
|
| 7 |
+
const axios = require('axios');
|
| 8 |
+
|
| 9 |
+
class CyberForgeMLClient {
|
| 10 |
+
constructor(baseUrl = 'http://localhost:8001') {
|
| 11 |
+
this.baseUrl = baseUrl;
|
| 12 |
+
this.client = axios.create({
|
| 13 |
+
baseURL: baseUrl,
|
| 14 |
+
timeout: 5000,
|
| 15 |
+
headers: { 'Content-Type': 'application/json' }
|
| 16 |
+
});
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
/**
|
| 20 |
+
* Get prediction from ML model
|
| 21 |
+
* @param {string} modelName - Name of the model
|
| 22 |
+
* @param {Object} features - Feature dictionary
|
| 23 |
+
* @returns {Promise<Object>} Prediction result
|
| 24 |
+
*/
|
| 25 |
+
async predict(modelName, features) {
|
| 26 |
+
try {
|
| 27 |
+
const response = await this.client.post('/predict', {
|
| 28 |
+
model_name: modelName,
|
| 29 |
+
features: features
|
| 30 |
+
});
|
| 31 |
+
return response.data;
|
| 32 |
+
} catch (error) {
|
| 33 |
+
console.error('ML prediction error:', error.message);
|
| 34 |
+
throw error;
|
| 35 |
+
}
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
/**
|
| 39 |
+
* Analyze website for threats
|
| 40 |
+
* @param {string} url - URL to analyze
|
| 41 |
+
* @param {Object} scrapedData - Data from WebScraperAPIService
|
| 42 |
+
* @returns {Promise<Object>} Threat analysis result
|
| 43 |
+
*/
|
| 44 |
+
async analyzeWebsite(url, scrapedData) {
|
| 45 |
+
try {
|
| 46 |
+
const response = await this.client.post('/analyze', {
|
| 47 |
+
url: url,
|
| 48 |
+
data: scrapedData
|
| 49 |
+
});
|
| 50 |
+
return response.data;
|
| 51 |
+
} catch (error) {
|
| 52 |
+
console.error('Website analysis error:', error.message);
|
| 53 |
+
throw error;
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
/**
|
| 58 |
+
* List available models
|
| 59 |
+
* @returns {Promise<Array>} List of model names
|
| 60 |
+
*/
|
| 61 |
+
async listModels() {
|
| 62 |
+
const response = await this.client.get('/models');
|
| 63 |
+
return response.data.models;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
/**
|
| 67 |
+
* Get model information
|
| 68 |
+
* @param {string} modelName - Name of the model
|
| 69 |
+
* @returns {Promise<Object>} Model metadata
|
| 70 |
+
*/
|
| 71 |
+
async getModelInfo(modelName) {
|
| 72 |
+
const response = await this.client.get(`/models/${modelName}`);
|
| 73 |
+
return response.data;
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
module.exports = CyberForgeMLClient;
|
phishing_detection/metadata.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_type": "random_forest",
|
| 3 |
+
"dataset": "phishing_detection",
|
| 4 |
+
"accuracy": 0.9889857732905002,
|
| 5 |
+
"f1_score": 0.9889844643474395,
|
| 6 |
+
"inference_time_ms": 0.010500483799549678,
|
| 7 |
+
"feature_names": [
|
| 8 |
+
"num_dots",
|
| 9 |
+
"subdomain_level",
|
| 10 |
+
"https",
|
| 11 |
+
"shortening_service",
|
| 12 |
+
"suspicious_words",
|
| 13 |
+
"is_phishing",
|
| 14 |
+
"url_url_length",
|
| 15 |
+
"url_domain_length",
|
| 16 |
+
"url_path_length",
|
| 17 |
+
"url_query_length",
|
| 18 |
+
"url_subdomain_count",
|
| 19 |
+
"url_domain_depth",
|
| 20 |
+
"url_suspicious_keyword_count",
|
| 21 |
+
"url_digit_count",
|
| 22 |
+
"url_special_char_count",
|
| 23 |
+
"url_hyphen_count",
|
| 24 |
+
"url_underscore_count",
|
| 25 |
+
"url_param_count",
|
| 26 |
+
"url_tld_length",
|
| 27 |
+
"url_has_subdomain",
|
| 28 |
+
"url_is_https",
|
| 29 |
+
"url_has_port",
|
| 30 |
+
"url_non_standard_port",
|
| 31 |
+
"url_has_ip_address",
|
| 32 |
+
"url_has_injection_pattern",
|
| 33 |
+
"url_at_symbol",
|
| 34 |
+
"url_has_query",
|
| 35 |
+
"url_is_common_tld"
|
| 36 |
+
],
|
| 37 |
+
"version": "1.0.0",
|
| 38 |
+
"framework": "sklearn"
|
| 39 |
+
}
|
phishing_detection/model.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a862118f7454849774b088a36e00d7fe238b5c728a4e602a6c3d794ac6152fd8
|
| 3 |
+
size 5135049
|
phishing_detection/package_info.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "phishing_detection",
|
| 3 |
+
"type": "random_forest",
|
| 4 |
+
"version": "1.0.0",
|
| 5 |
+
"accuracy": 0.9889857732905002,
|
| 6 |
+
"f1_score": 0.9889844643474395,
|
| 7 |
+
"inference_time_ms": 0.010500483799549678,
|
| 8 |
+
"files": {
|
| 9 |
+
"model": {
|
| 10 |
+
"path": "phishing_detection/model.pkl",
|
| 11 |
+
"checksum": "d71ee133bc3d72d097e8ae6c84733fb2",
|
| 12 |
+
"size_bytes": 5135049
|
| 13 |
+
},
|
| 14 |
+
"scaler": {
|
| 15 |
+
"path": "phishing_detection/scaler.pkl",
|
| 16 |
+
"checksum": "8dbf6376b3219801d6995268c7d5d05a"
|
| 17 |
+
},
|
| 18 |
+
"metadata": {
|
| 19 |
+
"path": "phishing_detection/metadata.json"
|
| 20 |
+
}
|
| 21 |
+
},
|
| 22 |
+
"packaged_at": "2026-02-15 19:21:08"
|
| 23 |
+
}
|
phishing_detection/scaler.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:67132bd0e3398d8006d2a1fbc0227e577e8e0beeb423a89ad55d10adf58c7205
|
| 3 |
+
size 2039
|
web_attack_detection/metadata.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_type": "random_forest",
|
| 3 |
+
"dataset": "web_attack_detection",
|
| 4 |
+
"accuracy": 1.0,
|
| 5 |
+
"f1_score": 1.0,
|
| 6 |
+
"inference_time_ms": 0.02898440998830613,
|
| 7 |
+
"feature_names": [
|
| 8 |
+
"response_code",
|
| 9 |
+
"is_attack",
|
| 10 |
+
"url_url_length",
|
| 11 |
+
"url_domain_length",
|
| 12 |
+
"url_path_length",
|
| 13 |
+
"url_query_length",
|
| 14 |
+
"url_subdomain_count",
|
| 15 |
+
"url_domain_depth",
|
| 16 |
+
"url_suspicious_keyword_count",
|
| 17 |
+
"url_digit_count",
|
| 18 |
+
"url_special_char_count",
|
| 19 |
+
"url_hyphen_count",
|
| 20 |
+
"url_underscore_count",
|
| 21 |
+
"url_param_count",
|
| 22 |
+
"url_tld_length",
|
| 23 |
+
"url_has_subdomain",
|
| 24 |
+
"url_is_https",
|
| 25 |
+
"url_has_port",
|
| 26 |
+
"url_non_standard_port",
|
| 27 |
+
"url_has_ip_address",
|
| 28 |
+
"url_has_injection_pattern",
|
| 29 |
+
"url_at_symbol",
|
| 30 |
+
"url_has_query",
|
| 31 |
+
"url_is_common_tld"
|
| 32 |
+
],
|
| 33 |
+
"version": "1.0.0",
|
| 34 |
+
"framework": "sklearn"
|
| 35 |
+
}
|
web_attack_detection/model.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f774d2935861a272513a885cc3d091c1d44dbc067e739590e8600bc335b127aa
|
| 3 |
+
size 285769
|
web_attack_detection/package_info.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "web_attack_detection",
|
| 3 |
+
"type": "random_forest",
|
| 4 |
+
"version": "1.0.0",
|
| 5 |
+
"accuracy": 1.0,
|
| 6 |
+
"f1_score": 1.0,
|
| 7 |
+
"inference_time_ms": 0.02898440998830613,
|
| 8 |
+
"files": {
|
| 9 |
+
"model": {
|
| 10 |
+
"path": "web_attack_detection/model.pkl",
|
| 11 |
+
"checksum": "3071f634875fa3a54b389667634b1afe",
|
| 12 |
+
"size_bytes": 285769
|
| 13 |
+
},
|
| 14 |
+
"scaler": {
|
| 15 |
+
"path": "web_attack_detection/scaler.pkl",
|
| 16 |
+
"checksum": "a511f6f966d0e45f2515732533dec192"
|
| 17 |
+
},
|
| 18 |
+
"metadata": {
|
| 19 |
+
"path": "web_attack_detection/metadata.json"
|
| 20 |
+
}
|
| 21 |
+
},
|
| 22 |
+
"packaged_at": "2026-02-15 19:21:08"
|
| 23 |
+
}
|
web_attack_detection/scaler.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f0f47a4d2ae1c388c1fd534b2fcb742c5e51aa7e2fdef963d887a08dc1d8986d
|
| 3 |
+
size 1879
|