UNPKG

breaker-ai

Version:

CLI to scan prompts for injection risks

149 lines (148 loc) 6.55 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const commander_1 = require("commander"); const scanPrompt_1 = require("../core/scanPrompt"); const package_json_1 = __importDefault(require("../../package.json")); const printTable_1 = require("./printTable"); const textMask_1 = require("../core/textMask"); const jailbreakPrompts_json_1 = __importDefault(require("../checks/jailbreakPrompts.json")); const cli_table3_1 = __importDefault(require("cli-table3")); const program = new commander_1.Command(); program .name("breaker") .description(`Prompt‑security scanner\n\nCommands:\n\n mask [options] <textOrFile>\n Mask sensitive words in a text or file.\n Example: breaker mask input.txt --words secret,password\n\n scan [options] <promptOrFile>\n Scan a prompt or file for risky patterns.\n Example: breaker scan prompt.txt --expected 80\n\n jailbreak [options] <systemPrompt>\n Run jailbreak prompts against a system prompt.\n Options:\n --prompts <file> Use a custom set of prompts (JSON array of {name, prompt})\n --skip <names> Comma-separated list of prompt names to skip\n Example: breaker jailbreak sys.txt --prompts my_prompts.json --skip ai_diagnostics,red_teaming\n\n list-prompts\n List all current jailbreak prompts as a table.\n Example: breaker list-prompts\n`) .version(package_json_1.default.version); const jailbreakChecklist_1 = require("../checks/jailbreakChecklist"); program .command("mask") .argument("<textOrFile>", "Text to mask or a file path") .option("-w, --words <words>", "Comma-separated list of words to mask", v => v.split(",")) .action(async (target, opts) => { const words = opts.words || []; const masked = await (0, textMask_1.maskWordsInText)(target, words); console.log(masked); }); program .command("scan") .argument("<promptOrFile>", "raw string or file path") .option("-j, --json", "output JSON") .option("-e, --expected <number>", "minimum expected score", v => parseInt(v, 10)) .action(async (target, opts) => { try { const result = await (0, scanPrompt_1.scanPrompt)(target); if (opts.json) { console.log(JSON.stringify(result, null, 2)); } else { (0, printTable_1.printTable)(result); } if (opts.expected !== undefined && result.score < opts.expected) { console.error(`\u001b[31mScore ${result.score} is less than expected ${opts.expected}\u001b[0m`); process.exit(1); } } catch (err) { console.error("\u001b[31m" + err + "\u001b[0m"); process.exit(1); } }); program .command("list-prompts") .description("List all current jailbreak prompts as a table") .action(() => { const table = new cli_table3_1.default({ head: ["#", "Name", "Prompt"], colWidths: [6, 24, 80], wordWrap: true, }); for (const item of jailbreakPrompts_json_1.default) { table.push([jailbreakPrompts_json_1.default.indexOf(item) + 1, item.name, item.prompt]); } console.log(table.toString()); }); program .command("jailbreak") .argument("<systemPrompt>", "System prompt string or file path") .option("-j,--json <file>", "Path to output JSON file") .option("-p, --prompts <file>", "Path to custom prompts JSON file (array of {name, prompt})") .option("-s, --skip <names>", "Comma-separated list of prompt names to skip", v => v.split(",")) .action(async (target, opts) => { let systemPrompt = target; const fs = await Promise.resolve().then(() => __importStar(require("fs/promises"))); try { if (await fs .stat(systemPrompt) .then(s => s.isFile()) .catch(() => false)) { systemPrompt = await fs.readFile(systemPrompt, "utf8"); } } catch (err) { console.error("\u001b[31m" + err + "\u001b[0m"); process.exit(1); } let customPrompts = undefined; if (opts.prompts) { try { const content = await fs.readFile(opts.prompts, "utf8"); customPrompts = JSON.parse(content); } catch (err) { console.error("\u001b[31mFailed to load custom prompts:\u001b[0m", err); process.exit(1); } } try { const report = await (0, jailbreakChecklist_1.runJailbreakChecklist)(systemPrompt, customPrompts, opts.skip); if (opts.json) { await fs.writeFile(opts.json, JSON.stringify(report, null, 2), "utf8"); } console.log(`Token usage:`); console.log(` Input tokens: ${report.totalPromptTokens}`); console.log(` Output tokens: ${report.totalCompletionTokens}`); console.log(` Total tokens: ${report.totalTokens}`); console.log(` Total cost (USD): $${report.totalCostUsd}`); } catch (err) { console.error("\u001b[31m" + err + "\u001b[0m"); process.exit(1); } }); program.parse();