Downloads · 30 days
0
C0d3Mast3r/honeySwarm_log_analyzer
honeySwarm_log_analyzer is a machine learning model from C0d3Mast3r. Use it for the machine learning task on the model card, and read the license before you ship it in a product. It is set up for sklearn. The card lists the license as mit.
Multi-label attack classifier for Cowrie SSH/Telnet honeypot sessions. Part of the HoneySwarm project — a Kubernetes-native honeypot platform with integrated ML-based attack analysis.
Downloads · 30 days
0
Access
Public
Updated Aug 27, 2026
Repo size
1.5 MB
Likes
0
Public
Click a slice to open those files.
.joblib1.5 MB · 95%
From the Hugging Face model README
Multi-label attack classifier for Cowrie SSH/Telnet honeypot sessions.
Part of the HoneySwarm project — a Kubernetes-native honeypot platform with integrated ML-based attack analysis.
Given a reconstructed Cowrie session (aggregated from raw JSON logs), the model predicts one or more attack labels, assigns a severity, and returns prevention recommendations.
It is not a standalone anomaly detector. It works alongside:
predicted_labels Can Be Empty (Evidence Guards Explained)The model outputs a raw probability for each label. A label only appears in predicted_labels if both conditions are true:
authentication_attack)The three evidence guards are:
| Label | Guard | Why |
|---|---|---|
authentication_attack | Session must have ≥ 3 failed logins | One or two failed attempts is noise; real brute-force has volume |
malware_download | Session must have a file download event or a wget/curl/tftp command | The model can pick up download-like language without an actual download happening |
tunneling_or_proxying | Session must have at least one direct-tcpip port-forward request | TCP tunneling leaves a specific protocol trace; text alone is unreliable |
What this means in practice: if the model is 99% confident about authentication_attack but the session only logged 1 failed login, the label is stripped and predicted_labels comes out []. This is intentional — it trades recall for precision, avoiding false positives on short or ambiguous sessions.
If you see predicted_labels: [] with high probabilities in probabilities_json, check these counters in your session:
failed_login_count < 3 → authentication_attack suppressedfile_download_count == 0 and no download command in command_text → malware_download suppresseddirect_tcpip_request_count == 0 → tunneling_or_proxying suppressedIf you discovered this model on Hugging Face and do not have access to the HoneySwarm repository, you can still test it directly on Cowrie logs.
python -m venv .venv
source .venv/bin/activate
pip install huggingface_hub
SNAPSHOT_DIR=$(python - <<'PY'
from huggingface_hub import snapshot_download
print(snapshot_download("C0d3Mast3r/honeySwarm_log_analyzer"))
PY
)
cd "$SNAPSHOT_DIR"
pip install -r requirements.txt
python hf_cowrie_runner.py \
--input /path/to/cowrie.json \
--output-dir ./hf_infer_output
cd "$SNAPSHOT_DIR"
python hf_cowrie_runner.py \
--input /path/to/cowrie_log_directory \
--output-dir ./hf_infer_output
Outputs are written to hf_infer_output/:
predictions.parquet (predicted labels and probabilities)sessions.parquet (reconstructed sessions)events.parquet (normalized events)Notes:
After each model upgrade, publish a new snapshot that includes both artifacts and runtime scripts.
From services/ai/:
python -m venv .venv
source .venv/bin/activate
pip install -e '.[publish]'
# Optional but recommended
pytest -q
# Smoke test direct local module path
python -m honeyswarm_ml.hf_infer \
--input /path/to/cowrie.json \
--output-directory dataset/processed/direct_hf_inference_smoke
Expected smoke-test artifacts:
dataset/processed/direct_hf_inference_smoke/predictions.parquetdataset/processed/direct_hf_inference_smoke/run_metadata.jsonModel artifacts:
artifact_manifest.jsonclassifiers.joblibword_vectorizer.joblibcharacter_vectorizer.joblibnumeric_scaler.jobliblabel_binarizer.joblibthresholds.jsonfeature_schema.jsonmodel_metadata.jsonproduction_thresholds.ymlRuntime scripts:
hf_cowrie_runner.pynormalize_events.pybuild_sessions.pypredict.pySupport files:
README.md (this model card)requirements.txtFrom services/ai/:
python publish_to_hf.py --model-dir models/candidates/<model_version_dir>
This command stages and uploads everything required. You should not manually upload files one-by-one.
In a clean virtual environment:
python -m venv .venv
source .venv/bin/activate
pip install huggingface_hub
SNAPSHOT_DIR=$(python - <<'PY'
from huggingface_hub import snapshot_download
print(snapshot_download("C0d3Mast3r/honeySwarm_log_analyzer"))
PY
)
cd "$SNAPSHOT_DIR"
pip install -r requirements.txt
python hf_cowrie_runner.py --input /path/to/cowrie.json --output-dir ./hf_infer_output
If this works, HF-only users can run inference without cloning the repository.
Commit and push these repository-side changes first:
src/honeyswarm_ml/hf_cowrie_runner.pypublish_to_hf.pyHF_README.mdmodels/candidates/<model_version_dir>Then run the publish command from your local machine.
| Label | Type | Notes |
|---|---|---|
authentication_attack | ML | Requires failed_login_count >= 3 |
reconnaissance | ML | |
data_collection | ML | |
malware_download | ML | Requires download event or downloader command |
malware_execution | ML | |
file_discovery | ML | |
defense_evasion | ML | |
persistence | ML | |
credential_access | ML | |
tunneling_or_proxying | ML | Requires direct_tcpip_request_count > 0 |
benign_or_noise | ML | Suppressed when any attack label is predicted |
configuration_tampering | Rule-only | |
suspicious_shell_activity | Rule-only | |
destructive_action | Rule-only | |
network_discovery | Rule-only | |
resource_hijacking | Rule-only | |
account_tampering | Rule-only |
1.0), rule-generated at reduced weight (0.35–0.75)| Dataset | Source | Sessions | Sensors |
|---|---|---|---|
| honeypot_logs_1 | Kaggle — Cowrie SSH/Telnet | 518,192 | 10 |
| honeypot_logs_2 | External Cowrie sensor (Apr–Jun 2021) | 612,527 | 1 |
Additional Kaggle references:
Raw logs, reviewed session CSVs, and model artifacts are not committed to Git. Only source code and configs are versioned.
v1.0 — model version 20260825T124742Z
External D2 macro F1: 0.7214
| Change | Version bump |
|---|---|
| F1 improves but stays in the same 10% band (e.g. 72% → 74%) | Minor: v1.1, v1.2, ... |
| F1 crosses a 10% boundary (e.g. 72% → 80%) | Major: v2.0 |
| F1 does not improve vs current published model | Not published |
Automated publishing uses this check:
if new_f1 < current_f1:
# do not publish
elif int(new_f1 * 10) > int(current_f1 * 10):
# major version bump
else:
# minor version bump
git clone https://github.com/dacharya/honeySwarm
cd honeySwarm/services/ai
pip install -e '.'
python -m honeyswarm_ml.normalize_events /path/to/your/cowrie/logs \
--dataset-name my_honeypot \
--output dataset/interim/events_mine.parquet
python -m honeyswarm_ml.build_sessions \
--events dataset/interim/events_mine.parquet \
--output dataset/processed/sessions_mine.parquet \
--memory-limit 4GB
from huggingface_hub import snapshot_download
import joblib, json
from pathlib import Path
model_dir = Path(snapshot_download("C0d3Mast3r/honeySwarm_log_analyzer"))
# Then run predict.py against your sessions:
python predict.py \
--sessions dataset/processed/sessions_mine.parquet \
--output dataset/processed/predictions_mine.parquet \
--model-directory <path to snapshot>
python -m honeyswarm_ml.apply_rules \
--sessions dataset/processed/sessions_mine.parquet \
--output dataset/processed/labels_mine.parquet
python -m honeyswarm_ml.build_verdicts \
--sessions dataset/processed/sessions_mine.parquet \
--rule-labels dataset/processed/labels_mine.parquet \
--predictions dataset/processed/predictions_mine.parquet \
--output dataset/processed/verdicts_mine.parquet
Verdicts contain: attack labels, severity, prevention recommendations, anomaly score, evidence JSON.
Add this to your server's crontab (crontab -e) to retrain every 3 days if new logs exist:
0 2 */3 * * /path/to/honeySwarm/services/ai/scripts/retrain_and_publish.sh >> /var/log/honeyswarm_retrain.log 2>&1
Create services/ai/scripts/retrain_and_publish.sh:
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")/.."
CURRENT_F1=0.7214 # update this after each successful publish
NEW_LOGS=/path/to/fresh/cowrie/logs
DATASET_NAME="my_honeypot_$(date +%Y%m%d)"
# Bail if no new logs
[ -d "$NEW_LOGS" ] || { echo "No new logs found."; exit 0; }
python -m honeyswarm_ml.normalize_events "$NEW_LOGS" \
--dataset-name "$DATASET_NAME" \
--output "dataset/interim/events_${DATASET_NAME}.parquet"
python -m honeyswarm_ml.build_sessions \
--events "dataset/interim/events_${DATASET_NAME}.parquet" \
--output "dataset/processed/sessions_${DATASET_NAME}.parquet" \
--memory-limit 4GB
python -m honeyswarm_ml.apply_rules \
--sessions "dataset/processed/sessions_${DATASET_NAME}.parquet" \
--output "dataset/processed/labels_${DATASET_NAME}.parquet"
python -m honeyswarm_ml.train_final_model
# Get latest candidate version dir
CANDIDATE=$(find models/candidates -mindepth 1 -maxdepth 1 -type d \
| grep -v anomaly | sort | tail -1)
python -m honeyswarm_ml.predict \
--sessions "dataset/processed/sessions_${DATASET_NAME}.parquet" \
--output "dataset/processed/preds_candidate.parquet" \
--model-directory "$CANDIDATE"
# Extract new F1
NEW_F1=$(python -c "
import json, sys
from pathlib import Path
from honeyswarm_ml.validate_external import *
# quick rule-reproduction check
import pyarrow.parquet as pq, numpy as np
from sklearn.metrics import f1_score
from sklearn.preprocessing import MultiLabelBinarizer
import yaml
config=yaml.safe_load(open('configs/training.yml'))
ml_labels=list(config['labels']['ml_labels'])
preds=pq.read_table('dataset/processed/preds_candidate.parquet',
columns=['session_key','predicted_labels']).to_pandas()
labels=pq.read_table('dataset/processed/labels_${DATASET_NAME}.parquet',
columns=['session_key','attack_labels']).to_pandas()
merged=preds.merge(labels,on='session_key',how='inner')
binarizer=MultiLabelBinarizer(classes=ml_labels)
binarizer.fit([ml_labels])
filt=lambda ls: [l for l in (ls.tolist() if hasattr(ls,'tolist') else list(ls)) if l in ml_labels]
truth=binarizer.transform(merged['attack_labels'].map(filt)).astype('int8')
pred=binarizer.transform(merged['predicted_labels'].map(filt)).astype('int8')
print(round(float(f1_score(truth,pred,average='macro',zero_division=0)),4))
")
echo "Current F1: $CURRENT_F1 | New F1: $NEW_F1"
# Compare and publish conditionally
python -c "
import sys
cur, new = float('$CURRENT_F1'), float('$NEW_F1')
if new < cur:
print('F1 did not improve. Skipping publish.')
sys.exit(1)
cur_band, new_band = int(cur * 10), int(new * 10)
if new_band > cur_band:
print(f'Major version bump: F1 {cur:.4f} -> {new:.4f}')
else:
print(f'Minor version bump: F1 {cur:.4f} -> {new:.4f}')
sys.exit(0)
" || exit 0
python publish_to_hf.py --model-dir "$CANDIDATE"
echo "Published $CANDIDATE (F1: $NEW_F1)"
Make it executable: chmod +x services/ai/scripts/retrain_and_publish.sh
After each successful publish, update CURRENT_F1 in the script to the new value.
from huggingface_hub import snapshot_download
import joblib, json
from pathlib import Path
from scipy.sparse import hstack, csr_matrix
import numpy as np
model_dir = Path(snapshot_download("C0d3Mast3r/honeySwarm_log_analyzer"))
word_vec = joblib.load(model_dir / "word_vectorizer.joblib")
char_vec = joblib.load(model_dir / "character_vectorizer.joblib")
scaler = joblib.load(model_dir / "numeric_scaler.joblib")
classifiers = joblib.load(model_dir / "classifiers.joblib")
schema = json.loads((model_dir / "feature_schema.json").read_text())
thresholds = json.loads((model_dir / "thresholds.json").read_text())["thresholds"]
labels = schema["labels"]
numeric_cols = schema["numeric_columns"]
text_col = schema["text_column"]
placeholder = schema["empty_text_placeholder"]
# Build features for a pandas DataFrame of sessions
def predict(sessions_df):
text = sessions_df[text_col].fillna(placeholder).replace("", placeholder).astype(str)
X = hstack([
word_vec.transform(text),
char_vec.transform(text),
csr_matrix(scaler.transform(
sessions_df[numeric_cols].apply(pd.to_numeric, errors="coerce").fillna(0).to_numpy(dtype=np.float32)
))
], format="csr", dtype=np.float32)
results = []
for i, label in enumerate(labels):
proba = classifiers[label].predict_proba(X)[:, 1]
results.append(proba >= thresholds[label])
return np.column_stack(results), labels
For the full inference pipeline including evidence guards, use
predict.pydirectly.
hf_cowrie_runner.py usage to run inference directly from raw Cowrie JSON input.HoneySwarm — https://github.com/dacharya/honeySwarm
Model: C0d3Mast3r/honeySwarm_log_analyzer