wormclaude 1.0.83 → 1.0.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -20,6 +20,7 @@ import { linkify } from './links.js';
20
20
  import { recordLearned } from './learn.js';
21
21
  import { loadSkills, getSkills, getSkill, buildSkillPrompt } from './skills.js';
22
22
  import { loadExtensions, getExtCommands, getExtCommand, buildExtCommandPrompt } from './extensions.js';
23
+ import { platformNote } from './subagents.js';
23
24
  import { COMMANDS, runSlashCommand } from './commands.js';
24
25
  import { tasks } from './tasks.js';
25
26
  import { connectMcpServers } from './mcp.js';
@@ -123,12 +124,12 @@ loadExtensions(); // extensions/<ad>/ (gömülü + kullanıcı + proje) yükle
123
124
  // Kalıcı hafıza: açılışta .wormclaude/memory.md + WORMCLAUDE.md'yi context'e yükle
124
125
  const _memCtx = loadMemoryContext();
125
126
  const _envContext = () => {
126
- const plat = process.platform === 'win32' ? 'Windows' : process.platform === 'darwin' ? 'macOS' : 'Linux';
127
- const shell = process.platform === 'win32' ? 'PowerShell (cmd.exe altinda calisir)' : 'bash/sh';
128
- const winNote = process.platform === 'win32'
129
- ? ' This is WINDOWS. Use Windows-correct commands. The Bash tool runs via cmd.exe so && chaining works, but do NOT assume a Unix shell: avoid grep/sed/awk/ls/cat — use the Read/Grep/Glob tools or PowerShell (Get-Content, Select-String, Get-ChildItem). Backslash paths are fine. AVOID interactive scaffolders that hang or are slow (create-react-app); prefer non-interactive, e.g. Vite: npm create vite@latest myapp -- --template react, then npm install. Always pass non-interactive flags (-y, --yes) when available.'
130
- : ' Use POSIX shell commands.';
131
- return `ENVIRONMENT: The user machine runs ${plat}. Bash tool shell: ${shell}. Current working directory: ${process.cwd()}.${winNote}`;
127
+ // Platform + kabuk kuralları paylaşılan kaynaktan (subagents.platformNote) ana ajan
128
+ // ve alt-ajanlar AYNI Windows tırnak/araç kurallarını görür.
129
+ const extra = process.platform === 'win32'
130
+ ? '\n- AVOID interactive scaffolders that hang (create-react-app); prefer Vite: npm create vite@latest myapp -- --template react.'
131
+ : '';
132
+ return platformNote() + extra;
132
133
  };
133
134
  const _initHistory = () => {
134
135
  const sys = [{ role: 'system', content: _envContext() }];
package/dist/commands.js CHANGED
@@ -15,6 +15,7 @@ import { isLearnEnabled, setLearnEnabled, getLearnFile, getLearnCount } from './
15
15
  import { saveMemoryFact, getMemoryPath, loadMemoryContext } from './memory.js';
16
16
  import { fetchAccount, getVerifyStatus, submitVerification } from './api.js';
17
17
  import { programText, tier } from './program.js';
18
+ import { runPentest } from './pentest.js';
18
19
  export const COMMANDS = [
19
20
  { name: '/help', desc: 'komutları ve ipuçlarını göster' },
20
21
  { name: '/clear', desc: 'sohbeti ve geçmişi temizle' },
@@ -44,6 +45,10 @@ export const COMMANDS = [
44
45
  { name: '/izinler', desc: 'onayli shell komutlarini yonet (list/add/remove/clear)' },
45
46
  { name: '/program', desc: 'Doğrulanmış Araştırmacı Programı — güven seviyeni göster' },
46
47
  { name: '/dogrula', desc: 'Doğrulanmış Araştırmacı başvurusu gönder: /dogrula <profil/şirket/gerekçe>' },
48
+ { name: '/recon', desc: '[seviye 3+] yetkili hedefte keşif (alt-alan/host/crawl): /recon <alan>' },
49
+ { name: '/scan', desc: '[seviye 3+] yetkili hedefte zafiyet taraması (nuclei): /scan <url>' },
50
+ { name: '/xss', desc: '[seviye 3+] yetkili hedefte XSS taraması (dalfox): /xss <url>' },
51
+ { name: '/sqli', desc: '[seviye 3+] yetkili hedefte SQLi taraması (sqlmap): /sqli <url>' },
47
52
  { name: '/export', desc: 'sohbeti dosyaya kaydet' },
48
53
  { name: '/resume', desc: 'en son kaydedilen oturumu yükle' },
49
54
  { name: '/quit', desc: 'çıkış' },
@@ -101,6 +106,85 @@ function tsStamp() {
101
106
  return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
102
107
  }
103
108
  // Komut yürütücü. true → komut işlendi, false → komut değil (normal mesaj).
109
+ const PT_LABELS = {
110
+ recon: 'Keşif (subfinder+httpx+katana)', scan: 'Zafiyet tarama (nuclei)',
111
+ xss: 'XSS (dalfox)', sqli: 'SQL injection (sqlmap)',
112
+ };
113
+ const PT_REASON = {
114
+ trust_required: 'Bu komut Doğrulanmış Araştırmacı (seviye 3+) gerektirir. Başvuru: /dogrula',
115
+ scope_required: 'Yetki onayı gerekli.',
116
+ no_quota: 'Bu ay tarama kotan yok (planını yükselt).',
117
+ quota_exceeded: 'Aylık tarama kotan doldu.',
118
+ invalid_target: 'Geçersiz hedef. URL/alan adı ver (örn https://test.com/p?id=1).',
119
+ unknown_tool: 'Bilinmeyen araç.',
120
+ auth: 'Giriş gerekli. /config key <anahtar>',
121
+ timeout: 'Sunucu zaman aşımı.',
122
+ upstream_error: 'Sunucuya ulaşılamadı.',
123
+ };
124
+ function formatFinding(x) {
125
+ const sev = x.severity ? `[${String(x.severity).toUpperCase()}] ` : '';
126
+ if (x.type === 'vuln')
127
+ return `${sev}${x.name || ''} — ${x.url || ''}`;
128
+ if (x.type === 'xss')
129
+ return `${sev}XSS ${x.param ? 'param ' + x.param : ''} — ${x.url || x.poc || ''}`;
130
+ if (x.type === 'sqli')
131
+ return `${sev}SQLi ${x.vulnerable ? 'ZAFİYETLİ' : ''} ${x.params ? '(' + x.params.join(',') + ')' : ''}`;
132
+ if (x.type === 'host')
133
+ return `${x.status || ''} ${x.url || ''}${x.title ? ' · ' + x.title : ''}${x.server ? ' · ' + x.server : ''}`;
134
+ if (x.value)
135
+ return `${x.value}`;
136
+ return JSON.stringify(x);
137
+ }
138
+ // /recon /scan /xss /sqli — ince runner'ı sürer. Zorunlu yetki onayı + trust 3+ teaser.
139
+ async function pentestCmd(tool, arg, ctx) {
140
+ const parts = (arg || '').trim().split(/\s+/).filter(Boolean);
141
+ let scopeAck = false;
142
+ if (parts.length && /^(onayla|--yes|-y|yes|evet)$/i.test(parts[parts.length - 1])) {
143
+ scopeAck = true;
144
+ parts.pop();
145
+ }
146
+ const target = parts.join(' ').trim();
147
+ const label = PT_LABELS[tool] || tool;
148
+ if (!target) {
149
+ ctx.note(`${label}\nKullanım: /${tool} <hedef>\nÖrnek: /${tool} https://test.com/sayfa?id=1`);
150
+ return;
151
+ }
152
+ if (!scopeAck) {
153
+ ctx.note(`⚠️ YETKİ ONAYI GEREKLİ — ${label}\n` +
154
+ `Hedef: ${target}\n\n` +
155
+ `Bu tarama hedefe GERÇEK istekler gönderir ve trafik SENİN IP'nden çıkar. Yalnız sahibi olduğun ya da\n` +
156
+ `yazılı izin/angajman bulunan sistemlerde çalıştır. Yetkisiz tarama yasa dışıdır ve kayıt altına alınır.\n\n` +
157
+ `Onaylıyorsan tekrar çalıştır: /${tool} ${target} onayla`);
158
+ return;
159
+ }
160
+ ctx.note(`${label} başlatılıyor — ${target}`);
161
+ const out = await runPentest(ctx.config, tool, target, true, (s) => ctx.note(s));
162
+ if (!out.ok) {
163
+ const r = out.reason || out.plan?.reason || 'error';
164
+ let msg = PT_REASON[r] || r;
165
+ if (r === 'quota_exceeded' && out.plan)
166
+ msg += ` (${out.plan.used}/${out.plan.quota})`;
167
+ ctx.note(`Tarama yapılamadı: ${msg}`);
168
+ return;
169
+ }
170
+ const rep = out.report || {};
171
+ const lines = [`✓ ${label} tamamlandı — ${rep.target || target}`];
172
+ if (out.missing && out.missing.length) {
173
+ lines.push(`⚠ Kurulu olmayan araç(lar) atlandı: ${out.missing.join(', ')}`);
174
+ }
175
+ const f = rep.findings || [];
176
+ if (!f.length) {
177
+ lines.push('Bulgu yok (hedef yanıt vermedi, temiz, ya da araç kurulu değil).');
178
+ }
179
+ else {
180
+ lines.push(`${rep.found_count} bulgu:`);
181
+ for (const x of f.slice(0, 40))
182
+ lines.push(' ' + formatFinding(x));
183
+ if (f.length > 40)
184
+ lines.push(` … +${f.length - 40} daha`);
185
+ }
186
+ ctx.assistant(lines.join('\n'));
187
+ }
104
188
  export async function runSlashCommand(input, ctx) {
105
189
  const v = input.trim();
106
190
  if (!v.startsWith('/'))
@@ -642,6 +726,12 @@ export async function runSlashCommand(input, ctx) {
642
726
  : `Başvuru gönderilemedi: ${res.error}`);
643
727
  return true;
644
728
  }
729
+ case '/recon':
730
+ case '/scan':
731
+ case '/xss':
732
+ case '/sqli':
733
+ await pentestCmd(cmd.slice(1), arg, ctx);
734
+ return true;
645
735
  case '/export': {
646
736
  fs.mkdirSync(SESSION_DIR, { recursive: true });
647
737
  const file = path.join(SESSION_DIR, `session-${tsStamp()}.json`);
@@ -0,0 +1,87 @@
1
+ // WormClaude güvenlik tarama — İSTEMCİ ince runner.
2
+ //
3
+ // Bu modül JENERİK bir çalıştırıcıdır: hiç payload/şablon/araç-seçimi içermez.
4
+ // Sunucudan bir komut PLANI alır, komutları YEREL makinede çalıştırır (trafik kullanıcının
5
+ // IP'sinden çıkar), ham çıktıyı sunucuya geri gönderir. Tüm zeka sunucuda kalır.
6
+ //
7
+ // Güvenlik: yalnız PT_ALLOWED'daki ikililer çalıştırılır (ele geçirilmiş/kötü sunucunun
8
+ // istemcide rastgele komut çalıştırmasını engeller). Komutlar SHELL'siz spawn edilir (enjeksiyon yok).
9
+ import { spawn } from 'node:child_process';
10
+ // İstemci-tarafı allowlist (sunucudakiyle aynı; çift güvence).
11
+ export const PT_ALLOWED = new Set(['httpx', 'nuclei', 'dalfox', 'sqlmap', 'subfinder', 'katana', 'nmap', 'ffuf']);
12
+ const MAX_OUT = 200_000;
13
+ async function postJson(config, p, body, timeoutMs) {
14
+ try {
15
+ const r = await fetch(`${config.baseUrl}${p}`, {
16
+ method: 'POST',
17
+ headers: { 'Content-Type': 'application/json', ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}) },
18
+ body: JSON.stringify(body),
19
+ signal: AbortSignal.timeout(timeoutMs),
20
+ });
21
+ const d = await r.json().catch(() => ({ ok: false, reason: 'bad_response' }));
22
+ if (!r.ok && !d.reason)
23
+ return { ok: false, reason: `HTTP ${r.status}` };
24
+ return d;
25
+ }
26
+ catch (e) {
27
+ return { ok: false, reason: e?.name === 'TimeoutError' ? 'timeout' : 'upstream_error' };
28
+ }
29
+ }
30
+ function runStep(step) {
31
+ return new Promise((resolve) => {
32
+ // İstemci allowlist zorlaması — sunucu ne derse desin, izinsiz ikili ÇALIŞMAZ.
33
+ if (!PT_ALLOWED.has(step.bin)) {
34
+ resolve({ id: step.id, ran: false, exit: -1, stdout: '', stderr: `engellendi: izinli olmayan ikili "${step.bin}"` });
35
+ return;
36
+ }
37
+ let out = '', err = '', done = false;
38
+ let child;
39
+ try {
40
+ child = spawn(step.bin, step.args, { shell: false, windowsHide: true });
41
+ }
42
+ catch {
43
+ resolve({ id: step.id, ran: false, exit: -1, stdout: '', stderr: `başlatılamadı (kurulu değil?): ${step.bin}` });
44
+ return;
45
+ }
46
+ const to = setTimeout(() => { try {
47
+ child.kill('SIGKILL');
48
+ }
49
+ catch { /* */ } }, Math.max(5, step.timeout) * 1000);
50
+ child.stdout?.on('data', (d) => { if (out.length < MAX_OUT)
51
+ out += d.toString(); });
52
+ child.stderr?.on('data', (d) => { if (err.length < 4000)
53
+ err += d.toString(); });
54
+ child.on('error', () => {
55
+ if (done)
56
+ return;
57
+ done = true;
58
+ clearTimeout(to);
59
+ resolve({ id: step.id, ran: false, exit: -1, stdout: out, stderr: `çalıştırılamadı (kurulu değil?): ${step.bin}` });
60
+ });
61
+ child.on('close', (code) => {
62
+ if (done)
63
+ return;
64
+ done = true;
65
+ clearTimeout(to);
66
+ resolve({ id: step.id, ran: true, exit: code ?? -1, stdout: out, stderr: err });
67
+ });
68
+ });
69
+ }
70
+ // Tam akış: plan al → yerelde çalıştır → rapor gönder. log() ile ilerleme bildirir.
71
+ export async function runPentest(config, tool, target, scopeAck, log) {
72
+ const plan = await postJson(config, '/pentest/plan', { tool, target, scope_ack: scopeAck }, 15000);
73
+ if (!plan.ok)
74
+ return { ok: false, reason: plan.reason, plan };
75
+ log(`Plan alındı (${plan.steps.length} adım). Yerelde çalıştırılıyor — trafik senin IP'nden çıkıyor…`);
76
+ const results = [];
77
+ const missing = [];
78
+ for (const s of plan.steps) {
79
+ log(` → ${s.bin} ${s.args.slice(0, 3).join(' ')}…`);
80
+ const r = await runStep(s);
81
+ if (!r.ran && /kurulu değil/.test(r.stderr))
82
+ missing.push(s.bin);
83
+ results.push(r);
84
+ }
85
+ const report = await postJson(config, '/pentest/report', { job_id: plan.job_id, results }, 30000);
86
+ return { ok: !!report.ok, plan, report, missing: [...new Set(missing)] };
87
+ }
package/dist/subagents.js CHANGED
@@ -4,6 +4,28 @@
4
4
  import * as fs from 'node:fs';
5
5
  import * as os from 'node:os';
6
6
  import * as path from 'node:path';
7
+ /**
8
+ * Çalışma ortamı + kabuk kuralları — hem ana ajana hem ALT-ajanlara verilir.
9
+ * Windows'ta cmd.exe tırnak kuralları kritik: yanlış tırnak sessizce "Sistem
10
+ * belirtilen dosyayı bulamıyor" / "URL rejected" ile patlar (curl 'url' başarısız).
11
+ */
12
+ export function platformNote() {
13
+ const isWin = process.platform === 'win32';
14
+ const plat = isWin ? 'Windows' : process.platform === 'darwin' ? 'macOS' : 'Linux';
15
+ const cwd = process.cwd();
16
+ if (isWin) {
17
+ return [
18
+ `ENVIRONMENT: User machine = Windows. The Bash tool runs commands via cmd.exe (NOT a Unix shell). CWD: ${cwd}.`,
19
+ 'WINDOWS SHELL RULES (critical — wrong quoting fails with "Sistem belirtilen dosyayı bulamıyor" or "URL rejected"):',
20
+ '- Use DOUBLE quotes only. SINGLE quotes do NOT work in cmd.exe — `curl \'http://x\'` FAILS.',
21
+ '- The characters < > & | ^ ( ) are special in cmd.exe; ANY argument or URL containing them MUST be wrapped in double quotes. Correct: curl "https://site/path?q=<script>alert(1)</script>" — never single-quoted, never unquoted.',
22
+ '- For fetching or probing a URL, PREFER the WebFetch tool (cross-platform, no shell quoting). Use curl.exe only when you need the RAW HTTP response (e.g. to see if an XSS payload is reflected verbatim), and ALWAYS double-quote the full URL.',
23
+ '- Unix/security tools are usually NOT installed (no grep/sed/awk/ls/cat/nmap/nikto/sqlmap). Use the Read/Grep/Glob tools or PowerShell (Get-Content, Select-String, Get-ChildItem). Before calling an external tool, verify it exists with `where <tool>`; if missing, use an HTTP/WebFetch-based method instead.',
24
+ '- && chaining works in cmd.exe. Always pass non-interactive flags (-y/--yes) to avoid hangs.',
25
+ ].join('\n');
26
+ }
27
+ return `ENVIRONMENT: User machine = ${plat}. Bash tool shell: bash/sh (POSIX). CWD: ${cwd}. Use POSIX commands and standard quoting; double-quote URLs containing special characters.`;
28
+ }
7
29
  // ── Gömülü uzman ajanlar ──────────────────────────────────────────────────────
8
30
  const BUILTINS = [
9
31
  {
package/dist/theme.js CHANGED
@@ -16,4 +16,4 @@ export const theme = {
16
16
  synType: '#a78bfa', // tip/sınıf adları, sabitler
17
17
  synProp: '#e0e0e0', // özellik/anahtar adları
18
18
  };
19
- export const VERSION = '1.0.83';
19
+ export const VERSION = '1.0.84';
package/dist/tools.js CHANGED
@@ -8,7 +8,7 @@ import * as os from 'node:os';
8
8
  import * as path from 'node:path';
9
9
  import { loadConfig } from './api.js';
10
10
  import { runAgentLoop } from './agent.js';
11
- import { resolveSubagent, subagentTypesHint } from './subagents.js';
11
+ import { resolveSubagent, subagentTypesHint, platformNote } from './subagents.js';
12
12
  import { saveMemoryFact } from './memory.js';
13
13
  import { emit as emitSpan } from './telemetry.js';
14
14
  import { tasks } from './tasks.js';
@@ -951,7 +951,7 @@ export async function executeTool(name, args) {
951
951
  if (name === 'Agent') {
952
952
  // Uzman ajan seçimi: subagent_type verilirse özel prompt + tool-kısıtı uygulanır.
953
953
  const def = resolveSubagent(args.subagent_type);
954
- const sysPrompt = def ? def.system : SUBAGENT_SYSTEM;
954
+ const sysPrompt = (def ? def.system : SUBAGENT_SYSTEM) + '\n\n' + platformNote();
955
955
  const subTools = subAgentTools(def?.tools);
956
956
  const subMessages = [
957
957
  { role: 'system', content: sysPrompt },
@@ -1391,7 +1391,7 @@ export async function executeTool(name, args) {
1391
1391
  if (sk.tools && sk.tools.length)
1392
1392
  tools = tools.filter((t) => sk.tools.includes(t.function.name));
1393
1393
  const messages = [
1394
- { role: 'system', content: SUBAGENT_SYSTEM },
1394
+ { role: 'system', content: SUBAGENT_SYSTEM + '\n\n' + platformNote() },
1395
1395
  { role: 'user', content: prompt },
1396
1396
  ];
1397
1397
  const { finalText } = await runAgentLoop({ config: cfg(), messages, tools, executeTool });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.83",
3
+ "version": "1.0.85",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {