"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;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.isSystemFilePath = isSystemFilePath;
exports.validateWritePath = validateWritePath;
exports.expandPath = expandPath;
exports.sanitizeFilePath = sanitizeFilePath;
exports.sanitizeCommand = sanitizeCommand;
exports.validateExecutionParams = validateExecutionParams;
const os = __importStar(require("os"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
// ── Windows System Path Protection ──
const SYSTEM_PATH_PREFIXES = [
"C:\\Windows\\",
"C:\\Program Files\\",
"C:\\Program Files (x86)\\",
"C:\\ProgramData\\",
"C:\\Users\\Public\\",
"C:\\Program Files (x86)\\Common Files\\",
"C:\\Program Files\\Common Files\\",
"C:\\Program Files\\WindowsApps\\",
"C:\\Program Files\\Windows Defender\\",
"C:\\Program Files\\Windows Mail\\",
"C:\\Program Files\\Windows Media Player\\",
"C:\\Program Files\\Windows NT\\",
"C:\\Program Files\\Windows Photo Viewer\\",
"C:\\Program Files\\Windows Portable Devices\\",
"C:\\Program Files\\Windows Security Health\\",
"C:\\Program Files\\Windows Sidebar\\",
"C:\\Program Files\\Windows Defender Advanced Threat Protection\\",
];
/**
* Check if a resolved absolute path points to a Windows system/protected location.
*/
function isSystemFilePath(resolvedPath) {
const normalized = resolvedPath.replace(/\\/g, "/").toLowerCase();
for (const prefix of SYSTEM_PATH_PREFIXES) {
if (normalized.startsWith(prefix.toLowerCase())) {
return true;
}
}
return false;
}
/**
* Validate that a path is safe for write/delete operations.
* Blocks writes to Windows system directories while allowing all other paths.
*/
function validateWritePath(filePath) {
const sanitization = sanitizeFilePath(filePath);
if (!sanitization.valid) {
return sanitization;
}
const resolved = sanitization.sanitized;
if (isSystemFilePath(resolved)) {
return { valid: false, error: `Write access denied: '${resolved}' is in a protected system directory` };
}
return { valid: true, sanitized: resolved };
}
// ── Original Functions ──
function expandPath(p) {
if (!p || typeof p !== "string")
return p;
let expanded = p.trim();
if (expanded.startsWith("~")) {
expanded = expanded.replace(/^~(?=[/\\]|$)/, os.homedir());
}
expanded = expanded.replace(/%([^%]+)%/g, (_, key) => process.env[key] ?? `%${key}%`);
return expanded;
}
function resolveExistingPath(expandedPath) {
try {
return fs.realpathSync(expandedPath);
}
catch {
const resolved = path.resolve(expandedPath);
const parent = path.dirname(resolved);
try {
const realParent = fs.realpathSync(parent);
return path.join(realParent, path.basename(resolved));
}
catch {
return resolved;
}
}
}
function sanitizeFilePath(filePath) {
if (!filePath || typeof filePath !== "string")
return { valid: false, error: "File path must be a non-empty string" };
const trimmed = filePath.trim();
if (trimmed.length === 0)
return { valid: false, error: "File path cannot be empty" };
if (trimmed.includes("\u0000"))
return { valid: false, error: "File path contains null character" };
if (trimmed.includes("..") && (trimmed.includes("/") || trimmed.includes("\\"))) {
return { valid: false, error: "File path traversal not allowed" };
}
const expanded = expandPath(trimmed);
const resolved = resolveExistingPath(expanded);
if (!resolved)
return { valid: false, error: "Failed to resolve file path" };
return { valid: true, sanitized: resolved };
}
function sanitizeCommand(command) {
if (!command || typeof command !== "string")
return { valid: false, error: "Command must be a non-empty string" };
const trimmed = command.trim();
if (trimmed.length === 0)
return { valid: false, error: "Command cannot be empty or whitespace-only" };
const dangerousKeywords = ["rm ", "del ", "format", "mkfs", "shutdown", "reboot", "rmdir", "rd "];
const separators = [";", "|", "&&", ">"];
for (const sep of separators) {
const partsOriginal = trimmed.split(sep);
if (partsOriginal.length > 1) {
for (const part of partsOriginal.slice(1)) {
const lowerPart = part.trim().toLowerCase();
for (const keyword of dangerousKeywords) {
if (part.trim().startsWith(keyword) || lowerPart.startsWith(keyword)) {
return { valid: false, error: "Command contains potentially dangerous patterns" };
}
}
}
}
}
const suspiciousPatterns = [/eval\s+/i, /source\s+/i];
for (const pattern of suspiciousPatterns) {
if (pattern.test(trimmed))
return { valid: false, error: "Command contains potentially risky patterns" };
}
return { valid: true, sanitized: trimmed };
}
function validateExecutionParams(params) {
const validated = { ...params };
if (params.timeoutMs !== undefined) {
const num = Number(params.timeoutMs);
if (!Number.isInteger(num) || num < 100 || num > 300000)
return { valid: false, error: "timeout_ms must be between 100 and 300000" };
}
if (params.maxOutputBytes !== undefined) {
const num = Number(params.maxOutputBytes);
if (!Number.isInteger(num) || num < 1024 || num > 104857600)
return { valid: false, error: "max_output_bytes must be between 1024 and 104857600" };
}
if (params.cwd !== undefined && typeof params.cwd === "string") {
try {
validated.cwd = expandPath(params.cwd);
}
catch {
return { valid: false, error: "Invalid cwd path" };
}
}
if (params.stdin !== undefined) {
if (typeof params.stdin !== "string")
return { valid: false, error: "stdin must be a string" };
if (params.stdin.length > 1_048_576)
return { valid: false, error: "stdin exceeds maximum size" };
}
if (params.env !== undefined) {
for (const [key, value] of Object.entries(params.env)) {
if (typeof key !== "string" || typeof value !== "string")
return { valid: false, error: "env values must be string-to-string" };
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key))
return { valid: false, error: `Invalid env var name: ${key}` };
}
}
if (params.args !== undefined) {
if (!Array.isArray(params.args))
return { valid: false, error: "args must be an array" };
for (const arg of params.args) {
if (typeof arg !== "string")
return { valid: false, error: "Each arg must be a string" };
if (arg.includes("\u0000"))
return { valid: false, error: "arg contains null character" };
}
}
return { valid: true, validated };
}
//# sourceMappingURL=securityEnhanced.js.map