// npm 패키지
@sdantu/bashbuddy
버전
1
메인테이너
1
라이선스
ISC
최초 publish
2026-06-03
publisher
sdantu
tarball
50,763 B
AUTO-PUBLISHED·1개 버전 인덱싱됨·최근 publish: 2026-06-03
// exfil path
what is read → where it shipssteals
- ○ system info
sends to
- ⚙ curl | bash(fetches + executes remote payload)
// offending code· @1.0.0· 3 files flagged
llm: malicious · 0.95→ 정적 분석기가 curl-pipe-bash 패턴 검출 — 설치 경로에 원격 코드 실행 형태가 그대로 드러남.
- @1.0.0··AUTO-PUBLISHED·publisher: sdantuheuristic 50/100static flags 3llm malicious (0.95) via fast-tracknew-publisher:0dfirst-version-of-packagefirst-version-suspicious-publisherchild-process-spawnreads-system-infocurl-pipe-bash
→ 정적 분석기가 curl-pipe-bash 패턴 검출 — 설치 경로에 원격 코드 실행 형태가 그대로 드러남.
// offending code· 3 files flaggedpatterns: 3
--- package/db.js (excerpt) --- import Database from 'better-sqlite3'; import { mkdirSync, existsSync } from 'fs'; import { join } from 'path'; import { homedir } from 'os'; const BASHBUDDY_DIR = join(homedir(), '.bashbuddy'); const DB_PATH = join(BASHBUDDY_DIR, 'db.sqlite'); if (!existsSync(BASHBUDDY_DIR)) mkdirSync(BASHBUDDY_DIR, { recursive: true }); const db = new Database(DB_PATH); // WAL mode — better performance, allows reads while writing db.pragma('journal_mode = WAL'); // ─── Schema ─────────────────────────────────────────────────────────────────── // Creates tables only if they don't already exist. // Safe to call every time bashbuddy starts. db.exec(` CREATE TABLE IF NOT EXISTS sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, started_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime')), ended_at TEXT ); CREATE TABLE IF NOT EXISTS commands ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL REFERENCES sessions(id), raw_input TEXT NOT NULL, command TEXT NOT NULL, executed_at TEXT NOT NULL DEFAULT (datetime('now', 'localtime')) ); `); // ─── Sessions ───────────────────────────────────────────────────────────────── // Call once when bashbuddy bash starts. // Returns the new session id. export function startSession() { const result = db.prepare(`INSERT INTO sessions DEFAULT VALUES`).run(); return result.lastInsertRowid; } // Call when bashbuddy closes. export function endSession(sessionId) { db --- package/detector.js (excerpt) --- import { createRequire } from 'module'; import { readFileSync, writeFileSync, existsSync } from 'fs'; import { join } from 'path'; import { homedir } from 'os'; // bash-parser is a CommonJS module — this is how you import CJS into ESM const require = createRequire(import.meta.url); const parse = require('bash-parser'); const LEARNED_COMMANDS_FILE = join(homedir(), '.bashbuddy', 'commands.json'); // ─── Known commands ─────────────────────────────────────────────────────────── // Hardcoded baseline — always present regardless of learned commands. const BASELINE_COMMANDS = new Set([ // filesystem 'ls', 'cd', 'pwd', 'mkdir', 'rmdir', 'rm', 'mv', 'cp', 'touch', 'ln', 'chmod', 'chown', 'chgrp', 'stat', 'file', 'find', 'du', 'df', // viewing 'cat', 'less', 'more', 'head', 'tail', 'open', // searching 'grep', 'awk', 'sed', 'sort', 'uniq', 'wc', 'diff', 'which', 'type', // system 'echo', 'printf', 'date', 'whoami', 'uname', 'uptime', 'ps', 'top', 'kill', 'pkill', 'env', 'export', 'unset', 'printenv', 'clear', 'exit', // network 'curl', 'wget', 'ssh', 'scp', 'rsync', 'ping', 'nc', // tools 'git', 'npm', 'npx', 'node', 'python', 'python3', 'pip', 'pip3', 'brew', 'gcc', 'vim', 'nano', 'code', 'tar', 'zip', 'unzip', 'gzip', 'gunzip', 'sudo', 'su', 'man', 'history', 'source', 'alias', ]); // ─── Runtime Set ───────────────────────────────────────────────────────────── // This is what shouldAttempt checks against. // Starts as the baseline, gets learned --- package/llm.js (excerpt) --- import { execSync, spawn } from 'child_process'; import { platform } from 'os'; const OLLAMA_BASE = 'http://localhost:11434'; const MODEL = 'llama3.2'; // ─── checkOllama ────────────────────────────────────────────────────────────── // Returns 1 only if BOTH conditions are true: // - Ollama server is running // - The model is pulled and ready // Returns 0 if either is missing. export async function checkOllama() { try { const res = await fetch(`${OLLAMA_BASE}/api/tags`, { signal: AbortSignal.timeout(2000) }); if (!res.ok) return 0; const data = await res.json(); const models = data.models || []; const modelReady = models.some(m => m.name.startsWith(MODEL)); if (!modelReady) { console.log(`[llm] Ollama running but model "${MODEL}" not found`); return 0; } return 1; } catch { return 0; } } // ─── installOllama ──────────────────────────────────────────────────────────── // Handles two cases: // 1. Ollama not installed → install it, start it, pull the model // 2. Ollama installed but model missing → just pull the model export async function installOllama() { const os = platform(); // Check if ollama binary exists at all const ollamaInstalled = isOllamaInstalled(); if (!ollamaInstalled) { console.log(`[llm] Ollama not installed — installing for platform: ${os}`); if (os === 'darwin') { console.log('[llm] running: brew install ollama'); try { execSync('brew install ollama',
