breaker-ai
Version:
CLI to scan prompts for injection risks
149 lines (148 loc) • 6.55 kB
JavaScript
;
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();