/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { randomBytes } from 'node:crypto';
export const INJECTION_PATTERNS = [
    { regex: /ignore\s+(all\s+)?(previous|prior|above)\s+instructions/i, name: 'ignore-instructions', severity: 'high' },
    { regex: /disregard\s+(all|everything|your)/i, name: 'disregard', severity: 'high' },
    { regex: /you\s+are\s+now/i, name: 'identity-override', severity: 'high' },
    { regex: /system\s+(prompt|override|message)/i, name: 'system-reference', severity: 'medium' },
    { regex: /act\s+as\s+(a\s+|an\s+)?/i, name: 'role-hijack', severity: 'medium' },
    { regex: /pretend\s+(you\s+are|to\s+be)/i, name: 'pretend', severity: 'medium' },
    {
        regex: /output\s+(all|the|your)\s+(env|environment|secret|key|token|password|credential)/i,
        name: 'exfiltration',
        severity: 'high',
    },
    { regex: /reveal\s+your\s+(instructions|prompt|system)/i, name: 'reveal', severity: 'high' },
    { regex: /<\/external-content>/i, name: 'boundary-escape', severity: 'high' },
    { regex: /<system>|<system-prompt>/i, name: 'fake-system-tag', severity: 'high' },
];
// ─── Core functions ───────────────────────────────────────────────────────────
/**
 * Detects prompt injection patterns in content.
 * Returns which patterns matched and the highest severity found.
 */
export function detectInjection(content) {
    const matched = [];
    let maxSeverity = 'low';
    for (const pattern of INJECTION_PATTERNS) {
        if (pattern.regex.test(content)) {
            matched.push(pattern.name);
            if (severityRank(pattern.severity) > severityRank(maxSeverity)) {
                maxSeverity = pattern.severity;
            }
        }
    }
    return {
        detected: matched.length > 0,
        patterns: matched,
        severity: matched.length > 0 ? maxSeverity : 'low',
    };
}
/**
 * Wraps content in trust boundary markers.
 */
export function wrapWithBoundary(content, metadata) {
    const idAttr = metadata.id ? ` id="${metadata.id}"` : '';
    const openTag = `<external-content source="${escapeAttr(metadata.source)}" trust="${metadata.trust}"${idAttr}>`;
    const closeTag = '</external-content>';
    return `${openTag}\n${content}\n${closeTag}`;
}
/**
 * Sanitizes content by detecting injection patterns and wrapping with trust boundaries.
 * The content field strips boundary-escape sequences; the wrapped field adds boundary markers.
 */
export function sanitize(content, source) {
    const injection = detectInjection(content);
    // Strip boundary escape attempts from content
    const sanitizedContent = content.replace(/<\/external-content>/gi, '&lt;/external-content&gt;');
    const wrapped = wrapWithBoundary(sanitizedContent, source);
    return {
        content: sanitizedContent,
        wrapped,
        injection,
    };
}
/**
 * Generates a cryptographically random canary token.
 * If the canary appears in output, it indicates content leakage.
 */
export function generateCanary() {
    return `__CANARY_${randomBytes(16).toString('hex')}__`;
}
/**
 * Checks if a canary token leaked into the output.
 */
export function checkCanaryLeak(output, canary) {
    return output.includes(canary);
}
// ─── Helpers ──────────────────────────────────────────────────────────────────
function severityRank(severity) {
    switch (severity) {
        case 'low':
            return 0;
        case 'medium':
            return 1;
        case 'high':
            return 2;
    }
}
function escapeAttr(value) {
    return value.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
//# sourceMappingURL=prompt-sanitizer.js.map