@inso_web/els-mcp
Version:
MCP-сервер поверх INSO Error Logs Service. Read-only tools (search, analytics, fingerprinting, correlations) для подключения Claude Desktop/Code и ChatGPT к логам ошибок. Streamable HTTP transport + stdio для npx-запуска.
65 lines • 2.99 kB
JavaScript
/**
* Prompt-injection mitigation:
* 1. Оборачиваем untrusted-контент в `<untrusted>...</untrusted>` теги.
* 2. Сканируем на regex-deny-list. При совпадении — флаг `suspicious=true`,
* вызывающий код может заменить контент на `<blocked: suspicious content>`.
* 3. При detect инкрементим Prometheus counter
* `mcp_prompt_injection_blocked_total{rule}`.
*/
import { recordPromptInjectionBlocked } from '../observability/metrics.js';
/** Regex-список «подозрительных» паттернов в untrusted-контенте. */
export const SUSPICIOUS_PATTERNS = [
{ name: 'ignore_previous', re: /ignore\s+(all\s+)?previous\s+(instructions?|messages?|prompts?)/i },
{ name: 'disregard_prior', re: /disregard\s+(all\s+)?(prior|previous)/i },
{ name: 'system_role', re: /(^|\W)system\s*:/i },
{ name: 'assistant_role', re: /(^|\W)assistant\s*:/i },
{ name: 'im_marker', re: /<\|im_(start|end)\|>/i },
{ name: 'inst_marker', re: /\[\/?INST\]/i },
{ name: 'you_are_now', re: /you\s+are\s+now\s+(a|an)\s+\w+/i },
{ name: 'override_rules', re: /override\s+your\s+(rules|instructions)/i },
{ name: 'jailbreak', re: /jailbreak/i },
];
const OPEN_TAG = '<untrusted>';
const CLOSE_TAG = '</untrusted>';
const ESCAPED_OPEN = '<untrusted>';
const ESCAPED_CLOSE = '</untrusted>';
/**
* Оборачивает строку в `<untrusted>`-теги. Если внутри уже есть точно
* такие же теги — экранируем их, чтобы не дать атакующему «закрыть»
* нашу обёртку.
*/
export function wrapUntrusted(text) {
if (text === null || text === undefined)
return null;
if (typeof text !== 'string')
return String(text);
if (text.length === 0)
return text;
const escaped = text.replace(/<untrusted>/gi, ESCAPED_OPEN).replace(/<\/untrusted>/gi, ESCAPED_CLOSE);
return `${OPEN_TAG}${escaped}${CLOSE_TAG}`;
}
/**
* Возвращает первое совпавшее правило или null. Не модифицирует строку.
*/
export function detectSuspicious(text) {
if (!text || typeof text !== 'string')
return null;
for (const { name, re } of SUSPICIOUS_PATTERNS) {
if (re.test(text)) {
// Метрика на каждое срабатывание.
try {
recordPromptInjectionBlocked(name);
}
catch {
// не блокируем основной flow при ошибке метрики
}
return { rule: name };
}
}
return null;
}
/** Удобный bool-обёртка вокруг `detectSuspicious`. */
export function containsSuspicious(text) {
return detectSuspicious(text) !== null;
}
//# sourceMappingURL=promptInjection.js.map