mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 23:44:33 +00:00
fix(security): harden account-key handling against prototype pollution
This commit is contained in:
@@ -12,12 +12,17 @@ import {
|
||||
import { resolveDiscordAccount } from "../../discord/accounts.js";
|
||||
import { resolveDiscordUserAllowlist } from "../../discord/resolve-users.js";
|
||||
import { resolveIMessageAccount } from "../../imessage/accounts.js";
|
||||
import { isBlockedObjectKey } from "../../infra/prototype-keys.js";
|
||||
import {
|
||||
addChannelAllowFromStoreEntry,
|
||||
readChannelAllowFromStore,
|
||||
removeChannelAllowFromStoreEntry,
|
||||
} from "../../pairing/pairing-store.js";
|
||||
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../routing/session-key.js";
|
||||
import {
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
normalizeAccountId,
|
||||
normalizeOptionalAccountId,
|
||||
} from "../../routing/session-key.js";
|
||||
import { resolveSignalAccount } from "../../signal/accounts.js";
|
||||
import { resolveSlackAccount } from "../../slack/accounts.js";
|
||||
import { resolveSlackUserAllowlist } from "../../slack/resolve-users.js";
|
||||
@@ -199,13 +204,22 @@ function resolveAccountTarget(
|
||||
const channels = (parsed.channels ??= {}) as Record<string, unknown>;
|
||||
const channel = (channels[channelId] ??= {}) as Record<string, unknown>;
|
||||
const normalizedAccountId = normalizeAccountId(accountId);
|
||||
if (isBlockedObjectKey(normalizedAccountId)) {
|
||||
return { target: channel, pathPrefix: `channels.${channelId}`, accountId: DEFAULT_ACCOUNT_ID };
|
||||
}
|
||||
const hasAccounts = Boolean(channel.accounts && typeof channel.accounts === "object");
|
||||
const useAccount = normalizedAccountId !== DEFAULT_ACCOUNT_ID || hasAccounts;
|
||||
if (!useAccount) {
|
||||
return { target: channel, pathPrefix: `channels.${channelId}`, accountId: normalizedAccountId };
|
||||
}
|
||||
const accounts = (channel.accounts ??= {}) as Record<string, unknown>;
|
||||
const account = (accounts[normalizedAccountId] ??= {}) as Record<string, unknown>;
|
||||
const existingAccount = Object.hasOwn(accounts, normalizedAccountId)
|
||||
? accounts[normalizedAccountId]
|
||||
: undefined;
|
||||
if (!existingAccount || typeof existingAccount !== "object") {
|
||||
accounts[normalizedAccountId] = {};
|
||||
}
|
||||
const account = accounts[normalizedAccountId] as Record<string, unknown>;
|
||||
return {
|
||||
target: account,
|
||||
pathPrefix: `channels.${channelId}.accounts.${normalizedAccountId}`,
|
||||
@@ -361,6 +375,14 @@ export const handleAllowlistCommand: CommandHandler = async (params, allowTextCo
|
||||
reply: { text: "⚠️ Unknown channel. Add channel=<id> to the command." },
|
||||
};
|
||||
}
|
||||
if (parsed.account?.trim() && !normalizeOptionalAccountId(parsed.account)) {
|
||||
return {
|
||||
shouldContinue: false,
|
||||
reply: {
|
||||
text: "⚠️ Invalid account id. Reserved keys (__proto__, constructor, prototype) are blocked.",
|
||||
},
|
||||
};
|
||||
}
|
||||
const accountId = normalizeAccountId(parsed.account ?? params.ctx.AccountId);
|
||||
const scope = parsed.scope;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user