language: en
license: apache-2.0
tags:
- cybersecurity
- instruction-tuning
- sft
- qwen3.8
- reasoning
- thinking-model
- agentic
- tool-calling
size_categories: 1K<n<10K
modalities: text
library: datasets
Cyber-SFT-Agent (Qwen3.8-27B Native) — v3.1 production (8.4K)
Agentic tool-calling SFT dataset for Qwen3.8-27B (abliterated or base).
Teaches the model to call real tools — masscan → nmap → curl → whatweb → nikto → ffuf → gobuster → dirb → wpscan → hydra → sqlmap → john → hashcat → searchsploit → metasploit → linpeas → winpeas → crackmapexec → enum4linux → responder → impacket → netcat — read their output, re-plan from the evidence,
and synthesize a ranked attack. Companion tohotdogs/cyber-sft-qa-qwen38
(the QA layer); this v3.1 ships the tool layer PLUS a sampled QA slice so it is
self-contained and composition-correct out of the box.
v3.1 what changed (vs v3, 7,000 rows)
- 7,000 → 8,400 rows (train 7,140 / valid 840 / test 420, stratified 30% tool each)
- 2,520 tool rows (seeds 1-140, 18 chains/seed) — 22 tools, 9 task types
- 5,880 QA rows sampled from the 72K QA repo
- (A) Evidence consistency — sqlmap now reports the actual backend DB of the
stack (MySQL / PostgreSQL / MSSQL, no moremysqllisted under PostgreSQL),
metasploit lands aswww-dataon Linux stacks andSYSTEMon Windows stacks,
nikto / curl / headers are stack-aware, hydra never targets a box with no SSH,
wpscan targets a WordPress stack, sqlmap targets a DB stack - (B) Negative evidence — 420 rows (16.7% of tool):
T7-dead-end: masscan → nmap → searchsploit, honest "no low-hanging fruit" reportT8-not-injectable: ffuf → sqlmap (5/5 payload classes, 0 hit) → pivot to /config.php credsT9-brute-fail-pivot: hydra fails onadmin→ wpscan findsdeploy→ hydra hits
- (C) Distractor palette — 38.5% of tool rows expose 2-5 extra context-appropriate
tool schemas the model must choose not to call (teaches tool selection) - Real-tokenizer length: p50=730, p95=1,584, p99=2,130, max=2,408 (0 over 4,096)
Composition (per spec)
| Metric | Value | Target | Status |
|---|---|---|---|
| rows | 8,400 | — | — |
| tool-calling rows | 30.0% (2,520) | ~30–36% | ✅ |
| multi-turn chains (≥2 calls) | 15.0% (1,260) | ≥10% | ✅ |
| QA rows | 70.0% (5,880) | ~64–70% | ✅ |
| think-tag coverage | 100% | 100% | ✅ |
| tool coverage | 100% (22/22 tools) | 0 leaks | ✅ |
| evidence chain (anti-boilerplate) | 100% | ≥60% | ✅ |
| duplicate rows | 0% | <1% | ✅ |
literal-\n in text |
0% | <5% | ✅ |
| negative-evidence rows | 16.7% of tool (420) | >0 (anti-hallucinate) | ✅ |
| distractor-palette rows | 38.5% of tool (971) | ~40% | ✅ |
| token length p50 / p95 / max (real tokenizer) | 730 / 1,584 / 2,408 | <4,096 | ✅ |
Byte-exact: all 8,400 rows re-rendered through the real Qwen3.8-27B chat
template (tokenizer Qwen2Tokenizer, vocab 248044) and verified
8,400/8,400 = 100%, 0 render errors.
Format (the important part)
Rendered through the real chat_template.jinja of Qwen3.8-27B and verified
byte-exact. The format facts (verified via byte ordinals — display lies about these):
| Fact | Value |
|---|---|
| Role tokens | backtick-wrapped: / (ord 60 124 im_start 124 62) |
| think OPEN | think — 7 chars, NO slash |
| think CLOSE | think/ — 8 chars, HAS slash (asymmetric, don't normalize) |
| tool call | XML: `tool_call` + `function=NAME` + `parameter=KEY` with value on its own line |
| tool result | role tool → rendered under a `user` wrapper block |
arguments |
a dict (template iterates .items()), not a JSON string |
Row schema
messages— template-native list, rolessystem/user/assistant/tool; thinking
inreasoning_content, calls intool_calls: [{name, arguments: {dict}}]
(use if your trainer callsapply_chat_template)text— the pre-rendered full template string (use for packing / single-text SFT)kind—tool(agentic chain) orqa(pure QA, zero tool_calls)tags,tools(function schemas),meta(n_tool_calls,n_turns,chain)
Splits (stratified — 30.0% tool in every split)
| Split | Rows | Tool rows | Tool% |
|---|---|---|---|
| train | 7,140 | 2,142 | 30.0% |
| valid | 840 | 252 | 30.0% |
| test | 420 | 126 | 30.0% |
Tool coverage (22/22)
nmap · masscan · curl · whatweb · nikto · ffuf · gobuster · dirb ·hydra · sqlmap · wpscan · searchsploit · metasploit · linpeas ·winpeas · crackmapexec · enum4linux · responder · impacket · john ·hashcat · netcat
Chain archetypes: T1 recon sweep → version detect → HTTP fingerprint; T2 version →
CVE triage → searchsploit → metasploit; T3 content discovery → parameter fuzz →
SQLi; T4 breach forensics → persistence confirmation; T5 Linux privesc (linpeas /
GTFOBins) + Windows privesc (winpeas / unquoted path); T6 lateral movement
(crackmapexec → enum4linux → responder) + hash-reuse pivot (impacket →
crackmapexec); T7 dead-end (hardened box, honest "no fruit" report);
T8 not-injectable (SQLi wall → pivot to /config.php creds); T9 brute-fail
(hydra misses admin → wpscan finds deploy → second hydra run hits).
Usage
A. messages[] (trainer calls apply_chat_template)
from datasets import load_dataset
ds = load_dataset("hotdogs/cyber-sft-agent-qwen38", split="train")
# trainer must use the Qwen3.8-27B chat template with:
# enable_thinking=True, preserve_thinking=True, reasoning_effort='xhigh'
B. text (packing / single-text SFT, no template needed — recommended)
ds = load_dataset("hotdogs/cyber-sft-agent-qwen38", split="train")
# tokenise ds["text"] directly; mask loss on the prompt prefix
Note for path A: the
messagescolumn goes through the HFdatasets
parquet layer, which unions theargumentsschema across tool rows — a call
that only used{target}may render extra<parameter=...>null</parameter>
entries when re-rendered frommessages. Thetextcolumn is byte-exact
(verified 8,400/8,400) and is the recommended training surface. If you train
onmessages, prefer the jsonl files over parquet, or drop thetoolsfield
before converting.
Recommended training config (Qwen3.8-27B, 4× RTX 3060 12GB)
lora: { r: 64, alpha: 128,
target_modules: [q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj] }
training:
seqlen: 4096 # covers 100% (real max 2,408 tok; 2048 covers 98.6%)
batch_size: 4
gradient_accumulation: 2
learning_rate: 2e-4
epochs: 3
Provenance
Generated by the qwen38-agent-toolcall skill pipeline v3.1 (Hermes Agent):gen_agent_rows_v2.py (seeds 1-140, 2,520 tool rows, 18 chains/seed) + mix_v2_production.py (5,880 QA sampled from hotdogs/cyber-sft-qa-qwen38) + sanitize_literal_newlines.py + verify_dataset_template.py + content_gates_agent.py + mix_composition.py.
QA slice source: Trendyol/Cybersecurity-Instruction + AlicanKiraz0/
Cybersecurity-Dataset-Fenrir-v2.1 (both Apache-2.0), converted by the QA pipeline.
Date anchor: 2026-08-18. Format ground truth: byte-ordinal analysis of the real template.