// engine/runtime-security/checkers/path-traversal.ts — SPEC-084 AC-02
// Detects and blocks path traversal attempts in tool inputs.
import path from 'node:path';
const DANGEROUS_SEQUENCES = ['../', '..\\', '%2e%2e', '%2E%2E', '%00', '\0'];
const SENSITIVE_DIRS_UNIX = ['/etc/', '/var/', '/usr/', '/bin/', '/sbin/', '/proc/', '/sys/'];
const SENSITIVE_DIRS_WIN = ['C:\\Windows\\', 'C:\\Program Files\\', 'C:\\System32\\'];
function isPotentialPath(value) {
    if (typeof value !== 'string') {
        return false;
    }
    return (value.includes('/') ||
        value.includes('\\') ||
        value.startsWith('~') ||
        value.startsWith('.') ||
        /^[A-Z]:/i.test(value));
}
function normalizePath(p) {
    let decoded = p;
    try {
        decoded = decodeURIComponent(decoded);
    }
    catch {
        // Already decoded or invalid encoding — keep as-is
    }
    return decoded.replace(/\\/g, '/');
}
function checkSinglePath(value, field, projectRoot) {
    const threats = [];
    const normalized = normalizePath(value);
    // Check dangerous sequences
    for (const seq of DANGEROUS_SEQUENCES) {
        if (normalized.includes(seq) || value.includes(seq)) {
            threats.push({
                type: 'path-traversal',
                severity: 'critical',
                message: `Path traversal sequence detected: "${seq}"`,
                field,
                pattern: seq,
            });
        }
    }
    // Check home directory escape
    if (normalized.startsWith('~/') || normalized.startsWith('~\\')) {
        threats.push({
            type: 'path-traversal',
            severity: 'critical',
            message: 'Home directory reference detected',
            field,
            pattern: '~/',
        });
    }
    // Check sensitive system directories
    const allSensitive = [...SENSITIVE_DIRS_UNIX, ...SENSITIVE_DIRS_WIN];
    for (const dir of allSensitive) {
        const normalizedDir = normalizePath(dir);
        if (normalized.startsWith(normalizedDir) ||
            normalized.toLowerCase().startsWith(normalizedDir.toLowerCase())) {
            threats.push({
                type: 'path-traversal',
                severity: 'critical',
                message: `Access to sensitive system directory: ${dir}`,
                field,
                pattern: dir,
            });
        }
    }
    // Check if resolved path escapes project root
    if (projectRoot && path.isAbsolute(value)) {
        const resolved = path.resolve(value);
        const resolvedRoot = path.resolve(projectRoot);
        if (!resolved.startsWith(resolvedRoot)) {
            threats.push({
                type: 'path-traversal',
                severity: 'critical',
                message: `Path resolves outside project root: ${resolved}`,
                field,
            });
        }
    }
    return threats;
}
export const pathTraversalChecker = {
    type: 'path-traversal',
    check(_toolName, inputs, _config) {
        const threats = [];
        const projectRoot = typeof inputs.projectPath === 'string' ? inputs.projectPath : undefined;
        for (const [key, value] of Object.entries(inputs)) {
            if (isPotentialPath(value)) {
                threats.push(...checkSinglePath(value, key, projectRoot));
            }
            if (Array.isArray(value)) {
                for (const item of value) {
                    if (isPotentialPath(item)) {
                        threats.push(...checkSinglePath(item, key, projectRoot));
                    }
                }
            }
        }
        return threats;
    },
};
//# sourceMappingURL=path-traversal.js.map