HomeJavaModsClientPolicy
ClientPolicy
ModsJava

ClientPolicy

by XenbleDev · on Modrinth

Server-side fingerprinting of client mods that announce themselves, with allowlist/blocklist profiles, a LOG → WARN → KICK ladder, and rules players can…

⬇ Download on Modrinth
ClientPolicy — screenshot 1ClientPolicy — screenshot 2

ClientPolicy

ClientPolicy identifies the client mods that announce themselves to your server, compares them against a policy profile you define, and applies a LOG → WARN → KICK ladder. Players can read the rules with /clientpolicy rules, so nobody gets kicked by a rule they were never shown.

No client-side mod is required. Vanilla, Fabric, Forge and NeoForge clients all work.


⚠️ Read this first: what ClientPolicy is not

ClientPolicy is not an anti-cheat.

Detection works by looking at three things the client volunteers:

  1. the plugin messaging channels it registers,
  2. its minecraft:brand string,
  3. the presence of a mod loader handshake.

A mod that never talks to the server is invisible to this method. X-ray, killaura, reach, freecam, auto-clickers and similar cheats register no channels and cannot be detected here.

What ClientPolicy does see reliably: Litematica, Xaero's Minimap/World Map, JourneyMap, VoxelMap, WorldEditCUI, Baritone, ReplayMod, Distant Horizons, Simple Voice Chat, Vivecraft, LabyMod, Lunar Client, and anything else you teach it.

This limit is repeated in config.yml, in /clientpolicy check and in /clientpolicy rules, on purpose. A policy tool that lets admins believe they have cheat detection is worse than no tool at all.


✨ Features

Deliberately out of scope: behavioural cheat detection, a client companion mod, resource pack enforcement, mod file hash verification, a web panel, MySQL.


✅ Step one: verify your signatures

Channel names change between Minecraft versions and mod releases. The shipped signatures.yml is a starting set, not ground truth. Confirm every entry you care about:

  1. Join with the mod installed on your own client.
  2. Run /clientpolicy inspect <yourname> and read the Unrecognised channels section.
  3. Copy those channels into a signatures.yml entry.
  4. /clientpolicy reload.

Do this before switching any profile to ALLOWLIST. In allowlist mode, an unverified signature list means kicking players for channels you simply never taught the plugin about.

/clientpolicy check is the same view limited to a player's own client, and is safe to leave available to everyone — it is what makes the policy auditable by the people it applies to.


🎮 Commands

Root command /clientpolicy, alias /cp.

Command Description Permission
/clientpolicy rules The allowed/denied mod list of your profile, grouped by category clientpolicy.rules (everyone)
/clientpolicy check What the server currently sees on your own client clientpolicy.check (everyone)
/clientpolicy inspect <player> Raw channels, brand, matched signatures, scan state clientpolicy.admin (op)
/clientpolicy history <player> [limit] Past detections and actions (default 10, max 100) clientpolicy.admin
/clientpolicy profile <player> Which profile a player resolved to, and why clientpolicy.admin
/clientpolicy rescan <player> Re-apply the policy immediately, ladder included clientpolicy.admin
/clientpolicy reload Reload config.yml and signatures.yml clientpolicy.admin

Permissions

Node Default Meaning
clientpolicy.rules everyone Use /clientpolicy rules
clientpolicy.check everyone Use /clientpolicy check
clientpolicy.admin op inspect, history, profile, rescan, reload
clientpolicy.bypass nobody Exempt from every action. Detections are still recorded and staff are still notified.
clientpolicy.notify op Receive a chat notification on every violation
clientpolicy.profile.<name> nobody Bind a player to the profile <name>

Assign clientpolicy.profile.<name> through a permissions plugin, and give exactly one per player or group — a player holding two profile permissions gets whichever is found first.


⚙️ Configuration

detection:
  scan-delay-ticks: 60          # first evaluation, 60 ticks = 3s after join
  rescan-window-seconds: 120    # new channels re-trigger evaluation for this long
  track-brand: true
  brand-unknown-action: LOG     # ALLOW | LOG | WARN | KICK, applied at window end

policy:
  default-profile: default
  unknown-channel-action: LOG   # keep this soft; it is the allowlist safety valve
  ignore-channels:              # never evaluated, supports * and ?
    - "minecraft:*"
    - "bungeecord:*"
    - "fabric:registry_sync"

enforcement:
  kick-message: |
    <red>A mod not permitted on this server was detected: <white><mod>
    <gray>Allowed mods: <aqua>/clientpolicy rules
  warn-message: "<gold>[!] <yellow><mod> <gray>is not permitted here. Next time you will be kicked."
  notify-staff: true
  notify-format: "<gray>[CP] <white><player> <gray>-> <red><mod> <dark_gray>(<action>)"

profiles:
  default:
    mode: BLOCKLIST             # ALLOWLIST | BLOCKLIST
    allow: [litematica, sodium, iris, worldeditcui, replaymod]
    deny:  [xaeros-minimap, journeymap, voxelmap, baritone]
    ladder:
      first: WARN
      after: KICK
      escalate-after: 2         # hits 1-2 WARN, hit 3 onwards KICK
      counter-reset-hours: 24
  builder:                      # clientpolicy.profile.builder
    mode: BLOCKLIST
    allow: [litematica, worldeditcui, sodium, iris, xaeros-minimap]
    deny:  [baritone]
    ladder:
      first: LOG
      after: WARN
      escalate-after: 3
      counter-reset-hours: 24

storage:
  retention-days: 30            # older records are pruned at startup

messages:
  prefix: "<dark_gray>[<aqua>ClientPolicy<dark_gray>] "

All messages use MiniMessage. Placeholders in kick-message, warn-message and notify-format: <player>, <mod>, <mod_id>, <channels>, <category>, <profile>, <reason>, <action>, <count> — where <reason> is one of DENIED, NOT_ALLOWED, UNKNOWN_CHANNEL, UNKNOWN_BRAND.

Only WARN and KICK are broadcast to clientpolicy.notify. LOG detections go to the console and to /clientpolicy history only — a single modded client easily brings a dozen uncatalogued channels, and broadcasting those would make the permission unusable.

Channels are never forgotten once registered: a client that registers and immediately unregisters has still revealed the mod.


🚀 Installation

  1. Drop ClientPolicy-<version>.jar into plugins/.
  2. Start the server. config.yml, signatures.yml and data.db are created in plugins/ClientPolicy/.
  3. Verify the signatures before you trust them — see the section above.
  4. Edit your profiles in config.yml, then run /clientpolicy reload.
Server Paper 1.21 – 1.21.11 (one jar for the whole line; no NMS, no reflection)
Java 21
Dependencies org.xerial:sqlite-jdbc, downloaded at runtime by Paper's library loader

If your server cannot reach Maven Central, the SQLite driver will not load. Detection and enforcement still work normally; only /clientpolicy history and the cross-session violation counter are disabled, and a warning is printed at startup.

Verified by MCModsHub

These come from our own check of the pack file, not from the source page.

Explore more