CVE-2022-23627 (C#, published 2022-02-08T23:15Z)
Description: value: ArchiSteamFarm (ASF) is a C# application with primary purpose of idling Steam cards from multiple accounts simultaneously. Due to a bug in ASF code, introduced in version V5.2.2.2, the program didn't adequately verify effective access of the user sending proxy (i.e. `[Bots]`) commands. In particular, a proxy-like command sent to bot `A` targeting bot `B` has incorrectly verified user's access against bot `A` - instead of bot `B`, to which the command was originally designated. This in result allowed access to resources beyond those configured, being a security threat affecting confidentiality of other bot instances. A successful attack exploiting this bug requires a significant access granted explicitly by original owner of the ASF process prior to that, as attacker has to control at least a single bot in the process to make use of this inadequate access verification loophole. The issue is patched in ASF V5.2.2.5, V5.2.3.2 and future versions. Users are advised to update as soon as possible.
Severity: MEDIUM (CVSS v3 base score: 6.8)
Weakness: CWE-863 \u2014 Incorrect Authorization
The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
Repository: https://github.com/JustArchiNET/ArchiSteamFarm
Files changed:
ArchiSteamFarm/Steam/Interaction/Commands.cs
Directory.Build.props
Commit message: Fix permissions when proxifying commands (#2509)

* Fix permissions when proxifying commands

* Version bump

Vulnerable code:
						return await ResponseStatus(access, SharedInfo.ASF).ConfigureAwait(false);
						return await Response2FA(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await Response2FAConfirm(access, Utilities.GetArgsAsText(args, 1, ","), false).ConfigureAwait(false);
						return await Response2FAConfirm(access, Utilities.GetArgsAsText(args, 1, ","), true).ConfigureAwait(false);
						return await ResponseAddLicense(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseWalletBalance(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseBackgroundGamesRedeemer(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseFarm(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseFarmingBlacklist(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseFarmingBlacklistAdd(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseFarmingBlacklistRemove(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseFarmingQueue(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseFarmingQueueAdd(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseFarmingQueueRemove(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseInput(access, args[1], args[2], Utilities.GetArgsAsText(message, 3)).ConfigureAwait(false);
						return await ResponseLevel(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseLoot(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseAdvancedLoot(access, args[1], args[2], Utilities.GetArgsAsText(message, 3)).ConfigureAwait(false);
						return await ResponseLootByRealAppIDs(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseLootByRealAppIDs(access, args[1]).ConfigureAwait(false);
						return await ResponseLootByRealAppIDs(access, args[1], Utilities.GetArgsAsText(args, 2, ","), true).ConfigureAwait(false);
						return await ResponseMatchActivelyBlacklist(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseMatchActivelyBlacklistAdd(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseMatchActivelyBlacklistRemove(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseNickname(access, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false);
						return await ResponseOwns(access, SharedInfo.ASF, Utilities.GetArgsAsText(message, 1)).ConfigureAwait(false);
						return await ResponseOwns(access, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false);
						return await ResponsePause(access, Utilities.GetArgsAsText(args, 1, ","), true).ConfigureAwait(false);
						return await ResponsePause(access, Utilities.GetArgsAsText(args, 1, ","), false).ConfigureAwait(false);
						return await ResponsePause(access, args[1], true, Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false);
						return await ResponsePlay(access, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false);
						return await ResponsePointsBalance(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponsePrivacy(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseRedeem(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseReset(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseResume(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseStart(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseStatus(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseStop(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseTradingBlacklist(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
						return await ResponseTradingBlacklistAdd(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseTradingBlacklistRemove(access, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false);
						return await ResponseTransfer(access, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false);
						return await ResponseAdvancedTransfer(access, args[1], args[2], args[3], Utilities.GetArgsAsText(message, 4)).ConfigureAwait(false);
						return await ResponseTransferByRealAppIDs(access, args[1], args[2], Utilities.GetArgsAsText(message, 3)).ConfigureAwait(false);
						return await ResponseTransferByRealAppIDs(access, args[1], args[2]).ConfigureAwait(false);
						return await ResponseTransferByRealAppIDs(access, args[1], args[2], Utilities.GetArgsAsText(message, 3), true).ConfigureAwait(false);
						return await ResponseUnpackBoosters(access, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false);
	private static async Task<string?> Response2FA(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.Response2FA(access))).ConfigureAwait(false);
	private static async Task<string?> Response2FAConfirm(EAccess access, string botNames, bool confirm) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.Response2FAConfirm(access, confirm))).ConfigureAwait(false);
	private static async Task<string?> ResponseAddLicense(EAccess access, string botNames, string query) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseAddLicense(access, query))).ConfigureAwait(false);
	private static async Task<string?> ResponseAdvancedLoot(EAccess access, string botNames, string appID, string contextID) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseAdvancedLoot(access, appID, contextID))).ConfigureAwait(false);
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseAdvancedRedeem(access, options, keys, steamID))).ConfigureAwait(false);
	private static async Task<string?> ResponseAdvancedTransfer(EAccess access, string botNames, string targetAppID, string targetContextID, string botNameTo) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseAdvancedTransfer(access, appID, contextID, targetBot))).ConfigureAwait(false);
	private static async Task<string?> ResponseBackgroundGamesRedeemer(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseBackgroundGamesRedeemer(access)))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarm(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseFarm(access))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingBlacklist(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingBlacklist(access)))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingBlacklistAdd(EAccess access, string botNames, string targetAppIDs) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingBlacklistAdd(access, targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingBlacklistRemove(EAccess access, string botNames, string targetAppIDs) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingBlacklistRemove(access, targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingQueue(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingQueue(access)))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingQueueAdd(EAccess access, string botNames, string targetAppIDs) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingQueueAdd(access, targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingQueueRemove(EAccess access, string botNames, string targetAppIDs) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingQueueRemove(access, targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseInput(EAccess access, string botNames, string propertyName, string inputValue) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseInput(access, propertyName, inputValue)))).ConfigureAwait(false);
	private static async Task<string?> ResponseLevel(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseLevel(access))).ConfigureAwait(false);
	private static async Task<string?> ResponseLoot(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseLoot(access))).ConfigureAwait(false);
	private async Task<string?> ResponseLootByRealAppIDs(EAccess access, string realAppIDsText, bool exclude = false) {
	private static async Task<string?> ResponseLootByRealAppIDs(EAccess access, string botNames, string realAppIDsText, bool exclude = false) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseLootByRealAppIDs(access, realAppIDsText, exclude))).ConfigureAwait(false);
	private static async Task<string?> ResponseMatchActivelyBlacklist(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseMatchActivelyBlacklist(access)))).ConfigureAwait(false);
	private static async Task<string?> ResponseMatchActivelyBlacklistAdd(EAccess access, string botNames, string targetAppIDs) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseMatchActivelyBlacklistAdd(access, targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseMatchActivelyBlacklistRemove(EAccess access, string botNames, string targetAppIDs) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseMatchActivelyBlacklistRemove(access, targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseNickname(EAccess access, string botNames, string nickname) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseNickname(access, nickname)))).ConfigureAwait(false);
	private static async Task<string?> ResponseOwns(EAccess access, string botNames, string query) {
		IList<(string? Response, Dictionary<string, string>? OwnedGames)> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseOwns(access, query))).ConfigureAwait(false);
	private static async Task<string?> ResponsePause(EAccess access, string botNames, bool permanent, string? resumeInSecondsText = null) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponsePause(access, permanent, resumeInSecondsText))).ConfigureAwait(false);
	private static async Task<string?> ResponsePlay(EAccess access, string botNames, string targetGameIDs) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponsePlay(access, targetGameIDs))).ConfigureAwait(false);
	private static async Task<string?> ResponsePointsBalance(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponsePointsBalance(access))).ConfigureAwait(false);
	private static async Task<string?> ResponsePrivacy(EAccess access, string botNames, string privacySettingsText) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponsePrivacy(access, privacySettingsText))).ConfigureAwait(false);
	private static async Task<string?> ResponseRedeem(EAccess access, string botNames, string keysText, ulong steamID = 0, ERedeemFlags redeemFlags = ERedeemFlags.None) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseRedeem(access, keysText, steamID, redeemFlags))).ConfigureAwait(false);
	private static async Task<string?> ResponseReset(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseReset(access))).ConfigureAwait(false);
	private static async Task<string?> ResponseResume(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseResume(access)))).ConfigureAwait(false);
	private static async Task<string?> ResponseStart(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseStart(access)))).ConfigureAwait(false);
	private static async Task<string?> ResponseStatus(EAccess access, string botNames) {
		IList<(string? Response, Bot Bot)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseStatus(access)))).ConfigureAwait(false);
	private static async Task<string?> ResponseStop(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseStop(access)))).ConfigureAwait(false);
	private static async Task<string?> ResponseTradingBlacklist(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseTradingBlacklist(access)))).ConfigureAwait(false);
	private static async Task<string?> ResponseTradingBlacklistAdd(EAccess access, string botNames, string targetSteamIDs) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseTradingBlacklistAdd(access, targetSteamIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseTradingBlacklistRemove(EAccess access, string botNames, string targetSteamIDs) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseTradingBlacklistRemove(access, targetSteamIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseTransfer(EAccess access, string botNames, string botNameTo) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseTransfer(access, botNameTo))).ConfigureAwait(false);
	private async Task<string?> ResponseTransferByRealAppIDs(EAccess access, IReadOnlyCollection<uint> realAppIDs, Bot targetBot, bool exclude = false) {
	private async Task<string?> ResponseTransferByRealAppIDs(EAccess access, string realAppIDsText, string botNameTo, bool exclude = false) {
	private static async Task<string?> ResponseTransferByRealAppIDs(EAccess access, string botNames, string realAppIDsText, string botNameTo, bool exclude = false) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseTransferByRealAppIDs(access, realAppIDs, targetBot, exclude))).ConfigureAwait(false);
	private static async Task<string?> ResponseUnpackBoosters(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseUnpackBoosters(access))).ConfigureAwait(false);
	private static async Task<string?> ResponseWalletBalance(EAccess access, string botNames) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseWalletBalance(access)))).ConfigureAwait(false);
		<Version>5.2.3.1</Version>

Fixed code:
						return await ResponseStatus(access, SharedInfo.ASF, steamID).ConfigureAwait(false);
						return await Response2FA(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await Response2FAConfirm(access, Utilities.GetArgsAsText(args, 1, ","), false, steamID).ConfigureAwait(false);
						return await Response2FAConfirm(access, Utilities.GetArgsAsText(args, 1, ","), true, steamID).ConfigureAwait(false);
						return await ResponseAddLicense(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseWalletBalance(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseBackgroundGamesRedeemer(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseFarm(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseFarmingBlacklist(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseFarmingBlacklistAdd(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseFarmingBlacklistRemove(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseFarmingQueue(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseFarmingQueueAdd(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseFarmingQueueRemove(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseInput(access, args[1], args[2], Utilities.GetArgsAsText(message, 3), steamID).ConfigureAwait(false);
						return await ResponseLevel(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseLoot(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseAdvancedLoot(access, args[1], args[2], Utilities.GetArgsAsText(message, 3), steamID).ConfigureAwait(false);
						return await ResponseLootByRealAppIDs(access, args[1], Utilities.GetArgsAsText(args, 2, ","), false, steamID).ConfigureAwait(false);
						return await ResponseLootByRealAppIDs(access, args[1], false).ConfigureAwait(false);
						return await ResponseLootByRealAppIDs(access, args[1], Utilities.GetArgsAsText(args, 2, ","), true, steamID).ConfigureAwait(false);
						return await ResponseMatchActivelyBlacklist(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseMatchActivelyBlacklistAdd(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseMatchActivelyBlacklistRemove(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseNickname(access, args[1], Utilities.GetArgsAsText(message, 2), steamID).ConfigureAwait(false);
						return await ResponseOwns(access, SharedInfo.ASF, Utilities.GetArgsAsText(message, 1), steamID).ConfigureAwait(false);
						return await ResponseOwns(access, args[1], Utilities.GetArgsAsText(message, 2), steamID).ConfigureAwait(false);
						return await ResponsePause(access, Utilities.GetArgsAsText(args, 1, ","), true, steamID: steamID).ConfigureAwait(false);
						return await ResponsePause(access, Utilities.GetArgsAsText(args, 1, ","), false, steamID: steamID).ConfigureAwait(false);
						return await ResponsePause(access, args[1], true, Utilities.GetArgsAsText(message, 2), steamID).ConfigureAwait(false);
						return await ResponsePlay(access, args[1], Utilities.GetArgsAsText(message, 2), steamID).ConfigureAwait(false);
						return await ResponsePointsBalance(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponsePrivacy(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseRedeem(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID: steamID).ConfigureAwait(false);
						return await ResponseReset(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseResume(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseStart(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseStatus(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseStop(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseTradingBlacklist(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
						return await ResponseTradingBlacklistAdd(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseTradingBlacklistRemove(access, args[1], Utilities.GetArgsAsText(args, 2, ","), steamID).ConfigureAwait(false);
						return await ResponseTransfer(access, args[1], Utilities.GetArgsAsText(message, 2), steamID).ConfigureAwait(false);
						return await ResponseAdvancedTransfer(access, args[1], args[2], args[3], Utilities.GetArgsAsText(message, 4), steamID).ConfigureAwait(false);
						return await ResponseTransferByRealAppIDs(access, args[1], args[2], Utilities.GetArgsAsText(message, 3), false, steamID).ConfigureAwait(false);
						return await ResponseTransferByRealAppIDs(access, args[1], args[2], false).ConfigureAwait(false);
						return await ResponseTransferByRealAppIDs(access, args[1], args[2], Utilities.GetArgsAsText(message, 3), true, steamID).ConfigureAwait(false);
						return await ResponseUnpackBoosters(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
	private static EAccess ProxyAccess(Bot bot, EAccess access, ulong steamID = 0) {
		// The objective here should be simple, calculating effective access of the user
		// Problem is, history already proved nothing in this damn file is as simple as it seems
		// We use this function for proxying commands such as !status 2 sent to bot 1, which should use 2's user access instead
		ArgumentNullException.ThrowIfNull(bot);

		if (!Enum.IsDefined(access)) {
			throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
		}

		if ((steamID != 0) && !new SteamID(steamID).IsIndividualAccount) {
			throw new ArgumentOutOfRangeException(nameof(steamID));
		}

		// If we got executed with owner access or lack steamID entirely, then this is effective access
		if ((access >= EAccess.Owner) || (steamID == 0)) {
			return access;
		}

		// Otherwise, effective access is the access of the user on target bot, whatever that would be, not this one
		return bot.GetAccess(steamID);
	}

	private static async Task<string?> Response2FA(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.Response2FA(ProxyAccess(bot, access, steamID)))).ConfigureAwait(false);
	private static async Task<string?> Response2FAConfirm(EAccess access, string botNames, bool confirm, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.Response2FAConfirm(ProxyAccess(bot, access, steamID), confirm))).ConfigureAwait(false);
	private static async Task<string?> ResponseAddLicense(EAccess access, string botNames, string query, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseAddLicense(ProxyAccess(bot, access, steamID), query))).ConfigureAwait(false);
	private static async Task<string?> ResponseAdvancedLoot(EAccess access, string botNames, string appID, string contextID, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseAdvancedLoot(ProxyAccess(bot, access, steamID), appID, contextID))).ConfigureAwait(false);
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseAdvancedRedeem(ProxyAccess(bot, access, steamID), options, keys, steamID))).ConfigureAwait(false);
	private static async Task<string?> ResponseAdvancedTransfer(EAccess access, string botNames, string targetAppID, string targetContextID, string botNameTo, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseAdvancedTransfer(ProxyAccess(bot, access, steamID), appID, contextID, targetBot))).ConfigureAwait(false);
	private static async Task<string?> ResponseBackgroundGamesRedeemer(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseBackgroundGamesRedeemer(ProxyAccess(bot, access, steamID))))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarm(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseFarm(ProxyAccess(bot, access, steamID)))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingBlacklist(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingBlacklist(ProxyAccess(bot, access, steamID))))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingBlacklistAdd(EAccess access, string botNames, string targetAppIDs, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingBlacklistAdd(ProxyAccess(bot, access, steamID), targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingBlacklistRemove(EAccess access, string botNames, string targetAppIDs, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingBlacklistRemove(ProxyAccess(bot, access, steamID), targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingQueue(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingQueue(ProxyAccess(bot, access, steamID))))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingQueueAdd(EAccess access, string botNames, string targetAppIDs, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingQueueAdd(ProxyAccess(bot, access, steamID), targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseFarmingQueueRemove(EAccess access, string botNames, string targetAppIDs, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseFarmingQueueRemove(ProxyAccess(bot, access, steamID), targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseInput(EAccess access, string botNames, string propertyName, string inputValue, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseInput(ProxyAccess(bot, access, steamID), propertyName, inputValue)))).ConfigureAwait(false);
	private static async Task<string?> ResponseLevel(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseLevel(ProxyAccess(bot, access, steamID)))).ConfigureAwait(false);
	private static async Task<string?> ResponseLoot(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseLoot(ProxyAccess(bot, access, steamID)))).ConfigureAwait(false);
	private async Task<string?> ResponseLootByRealAppIDs(EAccess access, string realAppIDsText, bool exclude) {
	private static async Task<string?> ResponseLootByRealAppIDs(EAccess access, string botNames, string realAppIDsText, bool exclude, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseLootByRealAppIDs(ProxyAccess(bot, access, steamID), realAppIDsText, exclude))).ConfigureAwait(false);
	private static async Task<string?> ResponseMatchActivelyBlacklist(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseMatchActivelyBlacklist(ProxyAccess(bot, access, steamID))))).ConfigureAwait(false);
	private static async Task<string?> ResponseMatchActivelyBlacklistAdd(EAccess access, string botNames, string targetAppIDs, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseMatchActivelyBlacklistAdd(ProxyAccess(bot, access, steamID), targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseMatchActivelyBlacklistRemove(EAccess access, string botNames, string targetAppIDs, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseMatchActivelyBlacklistRemove(ProxyAccess(bot, access, steamID), targetAppIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseNickname(EAccess access, string botNames, string nickname, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseNickname(ProxyAccess(bot, access, steamID), nickname)))).ConfigureAwait(false);
	private static async Task<string?> ResponseOwns(EAccess access, string botNames, string query, ulong steamID = 0) {
		IList<(string? Response, Dictionary<string, string>? OwnedGames)> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseOwns(ProxyAccess(bot, access, steamID), query))).ConfigureAwait(false);
	private static async Task<string?> ResponsePause(EAccess access, string botNames, bool permanent, string? resumeInSecondsText = null, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponsePause(ProxyAccess(bot, access, steamID), permanent, resumeInSecondsText))).ConfigureAwait(false);
	private static async Task<string?> ResponsePlay(EAccess access, string botNames, string targetGameIDs, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponsePlay(ProxyAccess(bot, access, steamID), targetGameIDs))).ConfigureAwait(false);
	private static async Task<string?> ResponsePointsBalance(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponsePointsBalance(ProxyAccess(bot, access, steamID)))).ConfigureAwait(false);
	private static async Task<string?> ResponsePrivacy(EAccess access, string botNames, string privacySettingsText, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponsePrivacy(ProxyAccess(bot, access, steamID), privacySettingsText))).ConfigureAwait(false);
	private static async Task<string?> ResponseRedeem(EAccess access, string botNames, string keysText, ERedeemFlags redeemFlags = ERedeemFlags.None, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseRedeem(ProxyAccess(bot, access, steamID), keysText, steamID, redeemFlags))).ConfigureAwait(false);
	private static async Task<string?> ResponseReset(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseReset(ProxyAccess(bot, access, steamID)))).ConfigureAwait(false);
	private static async Task<string?> ResponseResume(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseResume(ProxyAccess(bot, access, steamID))))).ConfigureAwait(false);
	private static async Task<string?> ResponseStart(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseStart(ProxyAccess(bot, access, steamID))))).ConfigureAwait(false);
	private static async Task<string?> ResponseStatus(EAccess access, string botNames, ulong steamID = 0) {
		IList<(string? Response, Bot Bot)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseStatus(ProxyAccess(bot, access, steamID))))).ConfigureAwait(false);
	private static async Task<string?> ResponseStop(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseStop(ProxyAccess(bot, access, steamID))))).ConfigureAwait(false);
	private static async Task<string?> ResponseTradingBlacklist(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseTradingBlacklist(ProxyAccess(bot, access, steamID))))).ConfigureAwait(false);
	private static async Task<string?> ResponseTradingBlacklistAdd(EAccess access, string botNames, string targetSteamIDs, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseTradingBlacklistAdd(ProxyAccess(bot, access, steamID), targetSteamIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseTradingBlacklistRemove(EAccess access, string botNames, string targetSteamIDs, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseTradingBlacklistRemove(ProxyAccess(bot, access, steamID), targetSteamIDs)))).ConfigureAwait(false);
	private static async Task<string?> ResponseTransfer(EAccess access, string botNames, string botNameTo, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseTransfer(ProxyAccess(bot, access, steamID), botNameTo))).ConfigureAwait(false);
	private async Task<string?> ResponseTransferByRealAppIDs(EAccess access, IReadOnlyCollection<uint> realAppIDs, Bot targetBot, bool exclude) {
	private async Task<string?> ResponseTransferByRealAppIDs(EAccess access, string realAppIDsText, string botNameTo, bool exclude) {
	private static async Task<string?> ResponseTransferByRealAppIDs(EAccess access, string botNames, string realAppIDsText, string botNameTo, bool exclude, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseTransferByRealAppIDs(ProxyAccess(bot, access, steamID), realAppIDs, targetBot, exclude))).ConfigureAwait(false);
	private static async Task<string?> ResponseUnpackBoosters(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseUnpackBoosters(ProxyAccess(bot, access, steamID)))).ConfigureAwait(false);
	private static async Task<string?> ResponseWalletBalance(EAccess access, string botNames, ulong steamID = 0) {
		IList<string?> results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.Commands.ResponseWalletBalance(ProxyAccess(bot, access, steamID))))).ConfigureAwait(false);
		<Version>5.2.3.2</Version>