/* * CSB Anti Exploit * Copyright (C) 2026 counter-strike-boost.com * * Validates client input to block classic HLDS/AMXX abuse: over-long client * commands, malformed setinfo keys, empty/over-long names and the fullupdate * spam vector. Offenders are logged and optionally kicked. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. It is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See for details. */ #include new const PLUGIN[] = "CSB Anti Exploit" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" new g_pEnabled, g_pMaxCmdLen, g_pMaxNameLen, g_pAction public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_antiexploit_enabled", "1") g_pMaxCmdLen = register_cvar("csb_antiexploit_maxcmd", "128") g_pMaxNameLen = register_cvar("csb_antiexploit_maxname", "32") g_pAction = register_cvar("csb_antiexploit_action", "1") // fullupdate spam is a well-known server-stress vector register_clcmd("fullupdate", "blockFullUpdate") } public blockFullUpdate(id) { return get_pcvar_num(g_pEnabled) ? PLUGIN_HANDLED : PLUGIN_CONTINUE } public client_command(id) { if (!get_pcvar_num(g_pEnabled) || !is_user_connected(id)) return PLUGIN_CONTINUE new cmd[64] read_argv(0, cmd, charsmax(cmd)) // chat lines can legitimately be long, so don't length-check them if (!equali(cmd, "say") && !equali(cmd, "say_team")) { new args[256] read_args(args, charsmax(args)) new maxLen = get_pcvar_num(g_pMaxCmdLen) if (maxLen > 0 && strlen(args) > maxLen) { punish(id, "over-long client command") return PLUGIN_HANDLED } } // malformed setinfo: empty key, or absurd key/value length if (equali(cmd, "setinfo")) { new key[128], val[128] read_argv(1, key, charsmax(key)) read_argv(2, val, charsmax(val)) if (!key[0] || strlen(key) > 63 || strlen(val) > 100) { punish(id, "malformed setinfo key/value") return PLUGIN_HANDLED } } return PLUGIN_CONTINUE } public client_infochanged(id) { if (!get_pcvar_num(g_pEnabled) || !is_user_connected(id)) return new newName[64] get_user_info(id, "name", newName, charsmax(newName)) // empty-name exploit: reset to a safe placeholder if (!newName[0]) { set_user_info(id, "name", "unnamed") log_amx("[CSB AntiExploit] reset an empty name from slot %d", id) return } new maxName = get_pcvar_num(g_pMaxNameLen) if (maxName > 0 && strlen(newName) > maxName) { // truncating re-fires client_infochanged, but the shorter name passes newName[maxName] = 0 set_user_info(id, "name", newName) log_amx("[CSB AntiExploit] truncated an over-long name from slot %d", id) } } punish(id, const reason[]) { new name[32], authid[35], ip[24] get_user_name(id, name, charsmax(name)) get_user_authid(id, authid, charsmax(authid)) get_user_ip(id, ip, charsmax(ip), 1) log_amx("[CSB AntiExploit] %s <%s> (%s) blocked: %s", name, authid, ip, reason) if (get_pcvar_num(g_pAction) == 1) { server_cmd("kick #%d ^"CSB Anti-Exploit: %s^"", get_user_userid(id), reason) server_exec() } }