fix(security): harden imessage remote scp/ssh handling

This commit is contained in:
Peter Steinberger
2026-02-19 11:07:56 +01:00
parent cdb00fe242
commit 49d0def6d1
12 changed files with 150 additions and 12 deletions

View File

@@ -1,4 +1,5 @@
import fs from "node:fs/promises";
import type { IMessagePayload, MonitorIMessageOpts } from "./types.js";
import { resolveHumanDelayConfig } from "../../agents/identity.js";
import { resolveTextChunkLimit } from "../../auto-reply/chunk.js";
import { hasControlCommand } from "../../auto-reply/command-detection.js";
@@ -18,6 +19,7 @@ import { recordInboundSession } from "../../channels/session.js";
import { loadConfig } from "../../config/config.js";
import { readSessionUpdatedAt, resolveStorePath } from "../../config/sessions.js";
import { danger, logVerbose, shouldLogVerbose } from "../../globals.js";
import { normalizeScpRemoteHost } from "../../infra/scp-host.js";
import { waitForTransportReady } from "../../infra/transport-ready.js";
import { mediaKindFromMime } from "../../media/constants.js";
import { buildPairingReply } from "../../pairing/pairing-messages.js";
@@ -39,7 +41,6 @@ import {
} from "./inbound-processing.js";
import { parseIMessageNotification } from "./parse-notification.js";
import { normalizeAllowList, resolveRuntime } from "./runtime.js";
import type { IMessagePayload, MonitorIMessageOpts } from "./types.js";
/**
* Try to detect remote host from an SSH wrapper script like:
@@ -146,10 +147,21 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
const dbPath = opts.dbPath ?? imessageCfg.dbPath;
const probeTimeoutMs = imessageCfg.probeTimeoutMs ?? DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS;
// Resolve remoteHost: explicit config, or auto-detect from SSH wrapper script
let remoteHost = imessageCfg.remoteHost;
// Resolve remoteHost: explicit config, or auto-detect from SSH wrapper script.
// Accept only a safe host token to avoid option/argument injection into SCP.
const configuredRemoteHost = normalizeScpRemoteHost(imessageCfg.remoteHost);
if (imessageCfg.remoteHost && !configuredRemoteHost) {
logVerbose("imessage: ignoring unsafe channels.imessage.remoteHost value");
}
let remoteHost = configuredRemoteHost;
if (!remoteHost && cliPath && cliPath !== "imsg") {
remoteHost = await detectRemoteHostFromCliPath(cliPath);
const detected = await detectRemoteHostFromCliPath(cliPath);
const normalizedDetected = normalizeScpRemoteHost(detected);
if (detected && !normalizedDetected) {
logVerbose("imessage: ignoring unsafe auto-detected remoteHost from cliPath");
}
remoteHost = normalizedDetected;
if (remoteHost) {
logVerbose(`imessage: detected remoteHost=${remoteHost} from cliPath`);
}