# Client Mod Verification on Schedule 1 Servers (/docs/schedule-1/client-mod-verification)



import { Callout } from 'fumadocs-ui/components/callout';
import { Step, Steps } from 'fumadocs-ui/components/steps';

The S1 DedicatedServerMod has a dedicated config file for client-mod policy: `client_mod_policy.toml`. It's how you keep cheaters or version-mismatched clients out, and how you make sure paired companion mods match exactly between server and client.

<Callout type="info">
  Authoritative reference: [docs.s1servers.com/configuration/client-mod-verification](https://docs.s1servers.com/).
</Callout>

***

What the policy can do [#what-the-policy-can-do]

Three deny-list arrays + two strict-mode tables:

| Block                                | What it does                                                                                |
| ------------------------------------ | ------------------------------------------------------------------------------------------- |
| `[policy].deniedClientModIds`        | Block by stable module ID (the canonical identifier mod authors register)                   |
| `[policy].deniedClientModNames`      | Block by display / assembly name (human-readable)                                           |
| `[policy].deniedClientModHashes`     | Block by exact SHA-256 of the mod's binary                                                  |
| `[approvedUnpairedClientMods.<id>]`  | Whitelist client-only mods (e.g. cosmetic mods that have no server side) with pinned hashes |
| `[strictPinnedCompanionHashes.<id>]` | Enforce that paired companion mods (server side + client side) have matching pinned hashes  |

The three deny arrays apply at all times. The two strict-mode tables let you pin exact hashes for trusted mods.

***

Deny specific mods [#deny-specific-mods]

Most common use case: block a known-cheat mod or a deprecated version.

```toml
[policy]
deniedClientModIds = ['example.badmod', 'example.legacycheat']
deniedClientModNames = ['Suspicious Visual Pack']
deniedClientModHashes = ['0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef']
```

A player whose client has *any* of these mods loaded will be rejected at connect with a policy violation reason.

Use IDs when you know the canonical identifier (most reliable), names for display-string matches (catches renamed variants), and hashes when you want to lock out a *specific* binary regardless of how it's labeled.

***

Approve unpaired client-only mods [#approve-unpaired-client-only-mods]

If a player wants to run a cosmetic / UI-only mod that doesn't exist server-side, it would normally fail the policy check (the server doesn't recognise it). Use `[approvedUnpairedClientMods]` to allow specific ones:

```toml
[approvedUnpairedClientMods.bars.visualtrees]
modId = 'bars.visualtrees'
displayName = 'Visual Trees'
pinnedSha256 = [
  'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
]

[approvedUnpairedClientMods.studio.chatcolors]
modId = 'studio.chatcolors'
displayName = 'Chat Colors'
pinnedSha256 = []
```

`pinnedSha256` can be:

* An empty array `[]` — approve any version of this mod (less strict)
* One or more hashes — approve only those specific binaries

***

Pin companion mod hashes (strict mode) [#pin-companion-mod-hashes-strict-mode]

For mods that have a paired server side and client side (e.g. content mods that ship both halves), pin the client hash to make sure nobody loads a tampered or wrong-version build:

```toml
[strictPinnedCompanionHashes.bars.mycoolmod]
modId = 'bars.mycoolmod'
pinnedSha256 = [
  'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
  'ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'
]
```

Two hashes means two versions are acceptable (e.g. during an upgrade window).

***

Edit the policy file [#edit-the-policy-file]

<Steps>
  <Step>
    Stop the server from the panel **Dashboard** (or restart later — policy edits don't have a dedicated hot reload command at the time of writing; check upstream docs if this changes).
  </Step>

  <Step>
    Open **File Manager** → edit `client_mod_policy.toml`.
  </Step>

  <Step>
    Add deny entries, approved-unpaired blocks, or strict pinned hashes as needed.
  </Step>

  <Step>
    Save and start the server.
  </Step>

  <Step>
    Test by connecting a client that should pass and one that should be rejected. The rejected client gets a specific policy violation reason — share that with players so they know what to remove or update.
  </Step>
</Steps>

***

Getting the hash of a mod [#getting-the-hash-of-a-mod]

To compute the SHA-256 of a mod DLL:

**On Windows (PowerShell):**

```powershell
Get-FileHash -Algorithm SHA256 path\to\Mod.dll
```

**On Linux / macOS:**

```bash
sha256sum path/to/Mod.dll
```

Copy the 64-character hex string into `pinnedSha256` or `deniedClientModHashes`.

***

Common patterns [#common-patterns]

Public modded server — block obvious cheats, allow cosmetics [#public-modded-server--block-obvious-cheats-allow-cosmetics]

```toml
[policy]
deniedClientModIds = ['known.cheat1', 'known.cheat2']

[approvedUnpairedClientMods.studio.chatcolors]
modId = 'studio.chatcolors'
displayName = 'Chat Colors'
pinnedSha256 = []
```

Private friend group — strict pinning on the mod stack you all use [#private-friend-group--strict-pinning-on-the-mod-stack-you-all-use]

```toml
[strictPinnedCompanionHashes.bars.multiplayerplus]
modId = 'bars.multiplayerplus'
pinnedSha256 = ['<sha of the exact MultiplayerPlus.dll you handed out>']

[strictPinnedCompanionHashes.bars.s1api]
modId = 'bars.s1api'
pinnedSha256 = ['<sha of the exact S1API.dll>']
```

Any client that doesn't match those hashes can't join — clean way to keep a tight modded server consistent.

Vanilla-only server [#vanilla-only-server]

```toml
[policy]
deniedClientModNames = ['*']
```

(Check upstream docs if wildcard deny is supported in the current schema — if not, you can list specific known mods. Permission denies in `permissions.toml` use wildcards; this file's wildcard behavior is less clear.)

***

Sharing the policy with players [#sharing-the-policy-with-players]

Before you enable strict pinning, send your players:

1. The exact mod DLLs they should install (zip the server-side `Mods/` folder via **File Manager** → right-click → **Archive** → **Download**).
2. A short note on how to install them — point them at [Install Mods](/docs/schedule-1/install-mods).

Otherwise their first connect attempt will fail and they won't know why.

***

Related Guides [#related-guides]

* [Install Mods →](/docs/schedule-1/install-mods)
* [MultiplayerPlus →](/docs/schedule-1/multiplayerplus)
* [Operators, Admins & TCP Console →](/docs/schedule-1/operators-admins)
* [Server Config Reference →](/docs/schedule-1/server-config)
* [Troubleshooting →](/docs/schedule-1/troubleshooting)
