import {
hasConfiguredUnavailableCredentialStatus,
hasResolvedCredentialValue,
} from "../channels/account-snapshot-fields.js"; import { resolveChannelDefaultAccountId } from "../channels/plugins/helpers.js"; import type { listChannelPlugins } from "../channels/plugins/index.js"; import type { ChannelId } from "../channels/plugins/types.public.js"; import { inspectReadOnlyChannelAccount } from "../channels/read-only-account-inspect.js"; import { formatCliCommand } from "../cli/command-format.js"; import { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { formatErrorMessage } from "../infra/errors.js"; import type { SecurityAuditFinding, SecurityAuditSeverity } from "./audit.types.js"; import { resolveDmAllowState } from "./dm-policy-shared.js";
function classifyChannelWarningSeverity(message: string): SecurityAuditSeverity { const s = message.toLowerCase(); if (
s.includes("dms: open") ||
s.includes('grouppolicy="open"') ||
s.includes('dmpolicy="open"')
) { return"critical";
} if (s.includes("allows any") || s.includes("anyone can dm") || s.includes("public")) { return"critical";
} if (s.includes("locked") || s.includes("disabled")) { return"info";
} return"warn";
}
function dedupeFindings(findings: SecurityAuditFinding[]): SecurityAuditFinding[] { const seen = new Set<string>(); const out: SecurityAuditFinding[] = []; for (const finding of findings) { const key = [
finding.checkId,
finding.severity,
finding.title,
finding.detail ?? "",
finding.remediation ?? "",
].join("\n"); if (seen.has(key)) { continue;
}
seen.add(key);
out.push(finding);
} return out;
}
if (dmScope === "main" && isMultiUserDm) {
findings.push({
checkId: `channels.${input.provider}.dm.scope_main_multiuser`,
severity: "warn",
title: `${input.label} DMs share the main session`,
detail: "Multiple DM senders currently share the main session, which can leak context across users.",
remediation: "Run: " +
formatCliCommand('openclaw config set session.dmScope "per-channel-peer"') + ' (or "per-account-channel-peer" for multi-account channels) to isolate DM sessions per sender.',
});
}
};
for (const plugin of params.plugins) { if (!plugin.security) { continue;
} const accountIds = plugin.config.listAccountIds(sourceConfig); const defaultAccountId = resolveChannelDefaultAccountId({
plugin,
cfg: sourceConfig,
accountIds,
}); const orderedAccountIds = Array.from(new Set([defaultAccountId, ...accountIds]));
for (const accountId of orderedAccountIds) { const hasExplicitAccountPath = hasExplicitProviderAccountConfig(
sourceConfig,
plugin.id,
accountId,
); const { account, enabled, configured, diagnostics } = await resolveChannelAuditAccount(
plugin,
accountId,
); for (const diagnostic of diagnostics) {
findings.push({
checkId: `channels.${plugin.id}.account.read_only_resolution`,
severity: "warn",
title: `${plugin.meta.label ?? plugin.id} account could not be fully resolved`,
detail: diagnostic,
remediation: "Ensure referenced secrets are available in this shell or run with a running gateway snapshot so security audit can inspect the full channel configuration.",
});
} if (!enabled) { continue;
} if (!configured) { continue;
}
const accountConfig = (account as { config?: Record<string, unknown> } | null | undefined)
?.config; if (isDangerousNameMatchingEnabled(accountConfig)) { const accountNote = formatChannelAccountNote({
orderedAccountIds,
hasExplicitAccountPath,
accountId,
});
findings.push({
checkId: `channels.${plugin.id}.allowFrom.dangerous_name_matching_enabled`,
severity: "info",
title: `${plugin.meta.label ?? plugin.id} dangerous name matching is enabled${accountNote}`,
detail: "dangerouslyAllowNameMatching=true re-enables mutable name/email/tag matching for sender authorization. This is a break-glass compatibility mode, not a hardened default.",
remediation: "Prefer stable sender IDs in allowlists, then disable dangerouslyAllowNameMatching.",
});
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.