{"id":116531,"date":"2026-06-06T23:35:48","date_gmt":"2026-06-06T20:35:48","guid":{"rendered":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/"},"modified":"2026-06-06T23:35:48","modified_gmt":"2026-06-06T20:35:48","slug":"opshield","status":"publish","type":"mod","link":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/","title":{"rendered":"OPShield"},"content":{"rendered":"<div align=\"center\">\n<p># \ud83d\udee1\ufe0f OPShield<\/p>\n<p>**Advanced security &#038; command protection plugin for Paper 1.21+**<\/p>\n<p>![Version]()<br \/>\n![Paper]()<br \/>\n![Java]()<br \/>\n![License]()<\/p>\n<p>*Protect your server from abuse \u2014 secure OP access, track every action, stop attackers instantly.*<\/p>\n<\/div>\n<p>&#8212;<\/p>\n<p>## \ud83d\udcd6 Table of Contents<\/p>\n<p>&#8211; \u2728 Features<br \/>\n&#8211; \ud83d\udd10 Security System<br \/>\n&#8211; \ud83d\udcca Audit &#038; Logging<br \/>\n&#8211; \ud83d\udce6 Requirements<br \/>\n&#8211; \ud83d\ude80 Installation<br \/>\n&#8211; \u2328\ufe0f Commands &#038; Permissions<br \/>\n&#8211; \ud83d\udd27 Configuration<br \/>\n&#8211; \ud83d\udd0d Troubleshooting<br \/>\n&#8211; \u2753 FAQ<br \/>\n&#8211; \ud83d\udcc4 Credits<\/p>\n<p>&#8212;<\/p>\n<p># \u2728 Features<\/p>\n<p>## \ud83d\udd12 OP Protection<\/p>\n<p>&#8211; Password-gated `\/op` and `\/deop` \u2014 no password, no privilege changes<br \/>\n&#8211; PBKDF2-HMAC-SHA256 hashed storage \u2014 plaintext never kept in config<br \/>\n&#8211; Configurable PBKDF2 iteration count (`security.password.pbkdf2_iterations`)<br \/>\n&#8211; Automatic migration from legacy plaintext and SHA-256 hashes<br \/>\n&#8211; **Auto-upgrade legacy hashes** \u2014 on next successful login, SHA-256 is silently replaced with PBKDF2 (`security.password.auto_upgrade_legacy_hash`)<br \/>\n&#8211; Console warning if a legacy SHA-256 hash is detected on startup<br \/>\n&#8211; OP whitelist \u2014 restrict `\/op` to a predefined set of player names<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83d\udeab Sensitive Command Protection<\/p>\n<p>&#8211; Block dangerous commands for non-OP players (`blocked_commands`)<br \/>\n&#8211; Optionally block commands even for OP players (`blocked_op_commands`)<br \/>\n&#8211; Block entire command namespaces via prefix list (`blocked_command_prefixes`)<br \/>\n&#8211; Alias and namespace resolution \u2014 bypass attempts via `minecraft:op` or plugin aliases are caught<br \/>\n&#8211; Per-player bypass permission (`opshield.bypass`) for trusted staff<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83e\udde0 Brute-force Detection &#038; Lockout<\/p>\n<p>&#8211; Configurable failed-attempt limit before lockout (`security.lockout.max-attempts`)<br \/>\n&#8211; Exponential backoff \u2014 each offence doubles the lockout duration<br \/>\n&#8211; Optional IP-mirrored lockout (`security.lockout.track_ip`)<br \/>\n&#8211; Lockout count decay after a cooling-off period (`security.lockout.count_decay_hours`)<br \/>\n&#8211; Persistent tracking \u2014 lockout state survives server restarts<br \/>\n&#8211; Manual unlock via `\/opshield unlock <player|ip>`<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83d\udd75\ufe0f Shadow Ban System<\/p>\n<p>&#8211; Sensitive blocked commands send a fake success message instead of an error<br \/>\n&#8211; Each trigger increments the player&#8217;s hidden shadow-ban level<br \/>\n&#8211; Level persists across restarts<br \/>\n&#8211; Auto-escalates to real punishment when `shadow_ban.auto_punish_level` is reached<br \/>\n&#8211; Set `auto_punish_level: 99` to keep decoy behaviour without escalation<br \/>\n&#8211; Fake messages come from language files \u2014 fully customisable per locale<\/p>\n<p>&#8212;<\/p>\n<p>## \u26a0\ufe0f Auto Punishment System<\/p>\n<p>&#8211; Punishment modes: `kick`, `ban`, `ban-ip`, `firewall`, `custom`<br \/>\n&#8211; Persistent rolling-window threshold \u2014 survives restarts and crashes<br \/>\n&#8211; Firewall mode runs an OS script asynchronously via `ProcessBuilder` with configurable timeout<br \/>\n&#8211; Custom mode supports `{player}` and `{ip}` placeholders<br \/>\n&#8211; IP-limit auto-punishment for accounts detected sharing the same IP<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83c\udf0d Multi-Language Support<\/p>\n<p>&#8211; Bundled language files: **English** (`en`), **Vietnamese** (`vn`), **Russian** (`ru`)<br \/>\n&#8211; Automatic fallback to English for any missing key<br \/>\n&#8211; Switch language via `language: &#8220;en&#8221;` in `config.yml`<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udcca Audit &#038; Logging<\/p>\n<p>&#8211; Every privilege change, password failure, command block, and punishment is logged<br \/>\n&#8211; Async queue \u2014 log writes never touch the main thread<br \/>\n&#8211; **Queue capacity limit** \u2014 `audit.max_queue_size` prevents OOM if disk writes fail for extended periods<br \/>\n&#8211; **Dual output format** \u2014 `audit.format: plain` (default human-readable) or `audit.format: json` (machine-readable, one JSON object per line)<br \/>\n&#8211; **UTF-8 safe** \u2014 uses NIO `Files.write()` with explicit charset<br \/>\n&#8211; **Retry on failure** \u2014 failed writes are re-queued instead of silently discarded<br \/>\n&#8211; Configurable rotation: `audit.max_file_size_mb` and `audit.log_retention` (up to N backup files)<br \/>\n&#8211; Optional console mirror: `audit.console_output: true`<br \/>\n&#8211; Log files: `plugins\/OPShield\/audit.log`, `audit.log.1` \u2026 `audit.log.N`<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udce6 Requirements<\/p>\n<p>| Component | Version |<br \/>\n|&#8212;&#8212;&#8212;&#8211;|&#8212;&#8212;&#8212;|<br \/>\n| Java      | 21+     |<br \/>\n| Paper     | 1.21+   |<br \/>\n| Folia     | \u274c Not supported |<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\ude80 Installation<\/p>\n<p>1. Download the plugin `.jar`<br \/>\n2. Drop it into your server&#8217;s `plugins\/` folder<br \/>\n3. Start the server \u2014 OPShield will generate a random password and print it **once** in the console<br \/>\n4. Save the password somewhere safe (it is only shown once)<br \/>\n5. **Grant permissions** \u2014 add `opshield.admin` to your admin group in your permission plugin (e.g. LuckPerms). OPShield no longer grants permissions based on OP status alone (changed in v1.8.0)<br \/>\n6. Open `plugins\/OPShield\/config.yml` to customise behaviour<br \/>\n7. Run `\/opshield reload` in-game or restart to apply changes \u2705<\/p>\n<p>> **Upgrading from 1.7.0?** `data.yml` is automatically migrated on first boot. You only need to update your permission plugin setup \u2014 see the CRITICAL note in the changelog.<\/p>\n<p>> **Tip:** If you already have an `op_password` plaintext value from an older version,<br \/>\n> OPShield will automatically migrate it to `op_password_hash` and remove the plaintext entry.<\/p>\n<p>&#8212;<\/p>\n<p># \u2328\ufe0f Commands<\/p>\n<p>| Command | Description |<br \/>\n|&#8212;&#8212;&#8212;|&#8212;&#8212;&#8212;&#8212;-|<br \/>\n| `\/op <player> [password]` | Grant OP with password verification |<br \/>\n| `\/deop <player> [password]` | Remove OP with password verification |<br \/>\n| `\/opshield reload` | Reload configuration |<br \/>\n| `\/opshield unlock <player|ip>` | Clear all tracking state for a player or IP |<br \/>\n| `\/opshield status` | Show runtime statistics (active levels, flagged IPs, etc.) |<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udd10 Permissions<\/p>\n<p>> \u26a0\ufe0f **Changed in v1.8.0:** All permissions now default to `false`. You must grant them explicitly via a permission plugin.<\/p>\n<p>| Permission | Default | Description |<br \/>\n|&#8212;&#8212;&#8212;&#8212;|&#8212;&#8212;&#8212;|&#8212;&#8212;&#8212;&#8212;-|<br \/>\n| `opshield.*` | false | Wildcard \u2014 grants all permissions |<br \/>\n| `opshield.admin` | false | Grants all child permissions |<br \/>\n| `opshield.reload` | false | Reload OPShield configuration |<br \/>\n| `opshield.unlock` | false | Unlock a tracked player or IP |<br \/>\n| `opshield.status` | false | View runtime statistics |<br \/>\n| `opshield.op` | false | Use password-protected `\/op` |<br \/>\n| `opshield.deop` | false | Use password-protected `\/deop` |<br \/>\n| `opshield.bypass` | false | Bypass non-OP restricted command blocking |<\/p>\n<p>### Example LuckPerms setup<br \/>\n&#8220;`bash<br \/>\n\/lp group admin permission set opshield.admin true<br \/>\n&#8220;`<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udd27 Configuration<\/p>\n<p>Files generated under `plugins\/OPShield\/`:<\/p>\n<p>&#8211; `config.yml` \u2014 main configuration<br \/>\n&#8211; `data.yml` \u2014 persistent runtime state (lockouts, shadow-ban levels, IP windows)<br \/>\n&#8211; `languages\/en.yml` \u2014 English messages<br \/>\n&#8211; `languages\/vn.yml` \u2014 Vietnamese messages<br \/>\n&#8211; `languages\/ru.yml` \u2014 Russian messages<\/p>\n<p>&#8212;<\/p>\n<p>## \u2699\ufe0f Key Config Options<\/p>\n<p>&#8220;`yaml<br \/>\n# Enable verbose console logging for troubleshooting (disable in production)<br \/>\ndebug: false<\/p>\n<p># Password security<br \/>\nsecurity:<br \/>\n  lockout:<br \/>\n    enabled: true<br \/>\n    max-attempts: 3<br \/>\n    duration-minutes: 3<br \/>\n    track_ip: true<br \/>\n    count_decay_hours: 168<br \/>\n  password:<br \/>\n    pbkdf2_iterations: 120000       # range: 10000 \u2013 1000000<br \/>\n    auto_upgrade_legacy_hash: true  # silently upgrade SHA-256 \u2192 PBKDF2 on login<\/p>\n<p># Auto-punishment<br \/>\nauto_punishment:<br \/>\n  enabled: true<br \/>\n  threshold: 5<br \/>\n  window_seconds: 300<br \/>\n  command: &#8220;kick&#8221;                   # kick | ban | ban-ip | firewall | custom<br \/>\n  firewall_timeout_seconds: 10<\/p>\n<p># Shadow ban<br \/>\nshadow_ban:<br \/>\n  enabled: true<br \/>\n  auto_punish_level: 5<\/p>\n<p># Audit log<br \/>\naudit:<br \/>\n  console_output: true<br \/>\n  max_file_size_mb: 5<br \/>\n  log_retention: 3<br \/>\n  max_queue_size: 10000             # 0 = unlimited (not recommended)<br \/>\n  format: &#8220;plain&#8221;                   # plain | json<br \/>\n&#8220;`<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83d\udcd0 Recommended settings by server size<\/p>\n<p>**Small server (\u2264 20 players)**<br \/>\n&#8220;`yaml<br \/>\nsecurity.lockout.max-attempts: 3<br \/>\nsecurity.lockout.duration-minutes: 5<br \/>\nip_limit.max_accounts: 2<br \/>\nauto_punishment.enabled: false<br \/>\nshadow_ban.auto_punish_level: 10<br \/>\n&#8220;`<\/p>\n<p>**Medium server (20\u2013100 players)**<br \/>\n&#8220;`yaml<br \/>\nsecurity.lockout.max-attempts: 3<br \/>\nsecurity.lockout.duration-minutes: 3<br \/>\nip_limit.max_accounts: 3<br \/>\nauto_punishment.enabled: true<br \/>\nauto_punishment.command: kick<br \/>\nauto_punishment.threshold: 5<br \/>\nshadow_ban.auto_punish_level: 5<br \/>\n&#8220;`<\/p>\n<p>**Large server (100+ players)**<br \/>\n&#8220;`yaml<br \/>\nsecurity.lockout.max-attempts: 2<br \/>\nsecurity.lockout.duration-minutes: 10<br \/>\nip_limit.max_accounts: 2<br \/>\nauto_punishment.enabled: true<br \/>\nauto_punishment.command: ban-ip<br \/>\nauto_punishment.threshold: 3<br \/>\nshadow_ban.auto_punish_level: 3<br \/>\n&#8220;`<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83d\udd25 Firewall mode setup<\/p>\n<p>Firewall mode executes an OS script asynchronously. To enable it:<\/p>\n<p>&#8220;`yaml<br \/>\nauto_punishment:<br \/>\n  command: &#8220;firewall&#8221;<br \/>\n  allow_unsafe_firewall_exec: true<br \/>\n  firewall_timeout_seconds: 10<br \/>\n  # Linux:<br \/>\n  firewall_script: &#8220;iptables -A INPUT -s {ip} -j DROP&#8221;<br \/>\n  # Windows:<br \/>\n  # firewall_script: &#8220;netsh advfirewall firewall add rule name=OPShield dir=in action=block remoteip={ip}&#8221;<br \/>\n&#8220;`<\/p>\n<p>If `allow_unsafe_firewall_exec` is `false`, firewall mode falls back to a safe kick.<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udd0d Troubleshooting<\/p>\n<details>\n<summary><b>Cannot use \/op \u2014 &#8220;Incorrect password&#8221;<\/b><\/summary>\n<p>The password is required. Run:<br \/>\n&#8220;`<br \/>\n\/op <yourname> <password>\n&#8220;`<br \/>\nIf you forgot the password, clear `op_password_hash` in `config.yml` and restart \u2014 a new password will be generated and printed in the console.<br \/>\n<\/details>\n<details>\n<summary><b>Admin cannot use \/opshield after upgrading from 1.7.0<\/b><\/summary>\n<p>In v1.8.0, permissions now default to `false` instead of `op`. You need to explicitly grant the permission:<br \/>\n&#8220;`bash<br \/>\n\/lp group admin permission set opshield.admin true<br \/>\n&#8220;`<br \/>\n<\/details>\n<details>\n<summary><b>Player is locked out and cannot try again<\/b><\/summary>\n<p>An admin can manually clear the lockout:<br \/>\n&#8220;`<br \/>\n\/opshield unlock <playername>\n\/opshield unlock <ip-address><br \/>\n&#8220;`<br \/>\n<\/details>\n<details>\n<summary><b>Auto-punishment is not triggering<\/b><\/summary>\n<p>Check the following:<br \/>\n&#8211; `auto_punishment.enabled: true` in `config.yml`<br \/>\n&#8211; The command the player used is listed in `auto_punishment.sensitive_commands`<br \/>\n&#8211; `shadow_ban.enabled` \u2014 if true, the player may be getting fake success messages first; level must reach `auto_punish_level`<br \/>\n&#8211; Run `\/opshield reload` after any config change<br \/>\n&#8211; Run `\/opshield status` to see current shadow-ban levels and punish state<br \/>\n<\/details>\n<details>\n<summary><b>Audit log is empty or not updating<\/b><\/summary>\n<p>&#8211; Check `audit.console_output: true` to confirm logging is active<br \/>\n&#8211; Check write permissions on the `plugins\/OPShield\/` folder<br \/>\n&#8211; If `audit.max_queue_size` is reached, a `SEVERE` warning appears in console \u2014 check disk space<br \/>\n<\/details>\n<details>\n<summary><b>Config changes are not taking effect<\/b><\/summary>\n<p>Run in-game or console:<br \/>\n&#8220;`<br \/>\n\/opshield reload<br \/>\n&#8220;`<br \/>\n<\/details>\n<p>&#8212;<\/p>\n<p># \u2753 FAQ<\/p>\n<p>### Does OPShield replace `\/op`?<br \/>\nNo \u2014 it intercepts and wraps it. The original `\/op` behaviour is preserved but gated behind a password.<\/p>\n<p>&#8212;<\/p>\n<p>### Is the password stored securely?<br \/>\nYes \u2014 passwords are hashed using PBKDF2-HMAC-SHA256 with a random salt and 120,000 iterations (configurable). The plaintext is never written to disk.<\/p>\n<p>&#8212;<\/p>\n<p>### Does it support Spigot or Folia?<br \/>\nPaper 1.21+ only. Spigot may work but is not tested. Folia is explicitly **not supported** (`folia-supported: false`).<\/p>\n<p>&#8212;<\/p>\n<p>### Can I disable auto-punishment entirely?<br \/>\nYes \u2014 set `auto_punishment.enabled: false`. Shadow-ban fake messages will still work independently.<\/p>\n<p>&#8212;<\/p>\n<p>### What happens if the server restarts during a lockout?<br \/>\nLockout state is persisted to `data.yml` and restored on startup. Players cannot bypass lockouts by crashing or restarting the server.<\/p>\n<p>&#8212;<\/p>\n<p>### Can I have multiple language files?<br \/>\nYes \u2014 all three bundled files (`en`, `vn`, `ru`) are always present. Switch via `language:` in `config.yml`. Missing keys automatically fall back to the bundled English defaults.<\/p>\n<p>&#8212;<\/p>\n<p>### What changed in v1.8.0?<br \/>\nThe most important change is **permission defaults** \u2014 see the [Changelog](CHANGELOG.md) for the full list. The short version: grant `opshield.admin` to your admin group in LuckPerms.<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udcc4 Credits<\/p>\n<p>**Author:** Duong2012G<br \/>\n**License:** Apache 2.0<br \/>\n**Website:** https:\/\/modrinth.com\/user\/Duong2012G<\/p>\n<p>*Built for secure, professional Minecraft servers.*<br \/>\n&#8211; Password-gated `\/op` and `\/deop` \u2014 no password, no privilege changes<br \/>\n&#8211; PBKDF2-HMAC-SHA256 hashed storage \u2014 plaintext never kept in config<br \/>\n&#8211; Configurable PBKDF2 iteration count (`security.password.pbkdf2_iterations`)<br \/>\n&#8211; Automatic migration from legacy plaintext and SHA-256 hashes<br \/>\n&#8211; Console warning if a legacy SHA-256 hash is detected on startup<br \/>\n&#8211; OP whitelist \u2014 restrict `\/op` to a predefined set of player names<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83d\udeab Sensitive Command Protection<\/p>\n<p>&#8211; Block dangerous commands for non-OP players (`blocked_commands`)<br \/>\n&#8211; Optionally block commands even for OP players (`blocked_op_commands`)<br \/>\n&#8211; Block entire command namespaces via prefix list (`blocked_command_prefixes`)<br \/>\n&#8211; Alias and namespace resolution \u2014 bypass attempts via `minecraft:op` or plugin aliases are caught<br \/>\n&#8211; Per-player bypass permission (`opshield.bypass`) for trusted staff<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83e\udde0 Brute-force Detection &#038; Lockout<\/p>\n<p>&#8211; Configurable failed-attempt limit before lockout (`security.lockout.max-attempts`)<br \/>\n&#8211; Exponential backoff \u2014 each offence doubles the lockout duration<br \/>\n&#8211; Optional IP-mirrored lockout (`security.lockout.track_ip`)<br \/>\n&#8211; Lockout count decay after a cooling-off period (`security.lockout.count_decay_hours`)<br \/>\n&#8211; Persistent tracking \u2014 lockout state survives server restarts<br \/>\n&#8211; Manual unlock via `\/opshield unlock <player|ip>`<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83d\udd75\ufe0f Shadow Ban System<\/p>\n<p>&#8211; Sensitive blocked commands send a fake success message instead of an error<br \/>\n&#8211; Each trigger increments the player&#8217;s hidden shadow-ban level<br \/>\n&#8211; Level persists across restarts<br \/>\n&#8211; Auto-escalates to real punishment when `shadow_ban.auto_punish_level` is reached<br \/>\n&#8211; Set `auto_punish_level: 99` to keep decoy behaviour without escalation<\/p>\n<p>&#8212;<\/p>\n<p>## \u26a0\ufe0f Auto Punishment System<\/p>\n<p>&#8211; Punishment modes: `kick`, `ban`, `ban-ip`, `firewall`, `custom`<br \/>\n&#8211; Persistent rolling-window threshold \u2014 survives restarts and crashes<br \/>\n&#8211; Firewall mode runs an OS script asynchronously via `ProcessBuilder` with configurable timeout<br \/>\n&#8211; Custom mode supports `{player}` and `{ip}` placeholders<br \/>\n&#8211; IP-limit auto-punishment for accounts detected sharing the same IP<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83c\udf0d Multi-Language Support<\/p>\n<p>&#8211; Bundled language files: **English** (`en`), **Vietnamese** (`vn`), **Russian** (`ru`)<br \/>\n&#8211; Automatic fallback to English for any missing key<br \/>\n&#8211; Switch language via `language: &#8220;en&#8221;` in `config.yml`<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udcca Audit &#038; Logging<\/p>\n<p>&#8211; Every privilege change, password failure, command block, and punishment is logged<br \/>\n&#8211; Async queue \u2014 log writes never touch the main thread<br \/>\n&#8211; **UTF-8 safe** \u2014 uses NIO `Files.write()` with explicit charset (fixed in 1.6.0)<br \/>\n&#8211; **Retry on failure** \u2014 failed writes are re-queued instead of silently discarded (fixed in 1.6.0)<br \/>\n&#8211; Configurable rotation: `audit.max_file_size_mb` and `audit.log_retention` (up to N backup files)<br \/>\n&#8211; Optional console mirror: `audit.console_output: true`<br \/>\n&#8211; Log files: `plugins\/OPShield\/audit.log`, `audit.log.1` \u2026 `audit.log.N`<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udce6 Requirements<\/p>\n<p>| Component | Version |<br \/>\n|&#8212;&#8212;&#8212;&#8211;|&#8212;&#8212;&#8212;|<br \/>\n| Java      | 21+     |<br \/>\n| Paper     | 1.21+   |<br \/>\n| Folia     | \u274c Not supported |<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\ude80 Installation<\/p>\n<p>1. Download the plugin `.jar`<br \/>\n2. Drop it into your server&#8217;s `plugins\/` folder<br \/>\n3. Start the server \u2014 OPShield will generate a random password and print it **once** in the console<br \/>\n4. Save the password somewhere safe (it is only shown once)<br \/>\n5. Open `plugins\/OPShield\/config.yml` to customise behaviour<br \/>\n6. Run `\/opshield reload` in-game or restart to apply changes \u2705<\/p>\n<p>> **Tip:** If you already have an `op_password` plaintext value from an older version,<br \/>\n> OPShield will automatically migrate it to `op_password_hash` and remove the plaintext entry.<\/p>\n<p>&#8212;<\/p>\n<p># \u2328\ufe0f Commands<\/p>\n<p>| Command | Description |<br \/>\n|&#8212;&#8212;&#8212;|&#8212;&#8212;&#8212;&#8212;-|<br \/>\n| `\/op <player> [password]` | Grant OP with password verification |<br \/>\n| `\/deop <player> [password]` | Remove OP with password verification |<br \/>\n| `\/opshield reload` | Reload configuration |<br \/>\n| `\/opshield unlock <player|ip>` | Clear all tracking state for a player or IP |<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udd10 Permissions<\/p>\n<p>| Permission | Default | Description |<br \/>\n|&#8212;&#8212;&#8212;&#8212;|&#8212;&#8212;&#8212;|&#8212;&#8212;&#8212;&#8212;-|<br \/>\n| `opshield.admin` | op | Grants all child permissions |<br \/>\n| `opshield.reload` | op | Reload OPShield configuration |<br \/>\n| `opshield.unlock` | op | Unlock a tracked player or IP |<br \/>\n| `opshield.op` | op | Use password-protected `\/op` |<br \/>\n| `opshield.deop` | op | Use password-protected `\/deop` |<br \/>\n| `opshield.bypass` | false | Bypass non-OP restricted command blocking |<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udd27 Configuration<\/p>\n<p>Files generated under `plugins\/OPShield\/`:<\/p>\n<p>&#8211; `config.yml` \u2014 main configuration<br \/>\n&#8211; `data.yml` \u2014 persistent runtime state (lockouts, shadow-ban levels, IP windows)<br \/>\n&#8211; `languages\/en.yml` \u2014 English messages<br \/>\n&#8211; `languages\/vn.yml` \u2014 Vietnamese messages<br \/>\n&#8211; `languages\/ru.yml` \u2014 Russian messages<\/p>\n<p>&#8212;<\/p>\n<p>## \u2699\ufe0f Example Config<\/p>\n<p>&#8220;`yaml<br \/>\n# Password security<br \/>\nsecurity:<br \/>\n  lockout:<br \/>\n    enabled: true<br \/>\n    max-attempts: 3<br \/>\n    duration-minutes: 3<br \/>\n    track_ip: true<br \/>\n    count_decay_hours: 168<br \/>\n  password:<br \/>\n    pbkdf2_iterations: 120000   # range: 10000 \u2013 1000000<\/p>\n<p># Auto-punishment<br \/>\nauto_punishment:<br \/>\n  enabled: true<br \/>\n  threshold: 5<br \/>\n  window_seconds: 300<br \/>\n  command: &#8220;kick&#8221;               # kick | ban | ban-ip | firewall | custom<br \/>\n  firewall_timeout_seconds: 10<\/p>\n<p># Shadow ban<br \/>\nshadow_ban:<br \/>\n  enabled: true<br \/>\n  auto_punish_level: 3<\/p>\n<p># Audit log<br \/>\naudit:<br \/>\n  console_output: true<br \/>\n  max_file_size_mb: 5<br \/>\n  log_retention: 3<br \/>\n&#8220;`<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83d\udcd0 Recommended settings by server size<\/p>\n<p>**Small server (\u2264 20 players)**<br \/>\n&#8220;`yaml<br \/>\nsecurity.lockout.max-attempts: 3<br \/>\nsecurity.lockout.duration-minutes: 5<br \/>\nip_limit.max_accounts: 2<br \/>\nauto_punishment.enabled: false<br \/>\n&#8220;`<\/p>\n<p>**Medium server (20\u2013100 players)**<br \/>\n&#8220;`yaml<br \/>\nsecurity.lockout.max-attempts: 3<br \/>\nsecurity.lockout.duration-minutes: 3<br \/>\nip_limit.max_accounts: 3<br \/>\nauto_punishment.enabled: true<br \/>\nauto_punishment.command: kick<br \/>\nauto_punishment.threshold: 5<br \/>\nshadow_ban.auto_punish_level: 3<br \/>\n&#8220;`<\/p>\n<p>**Large server (100+ players)**<br \/>\n&#8220;`yaml<br \/>\nsecurity.lockout.max-attempts: 2<br \/>\nsecurity.lockout.duration-minutes: 10<br \/>\nip_limit.max_accounts: 2<br \/>\nauto_punishment.enabled: true<br \/>\nauto_punishment.command: ban-ip<br \/>\nauto_punishment.threshold: 3<br \/>\nshadow_ban.auto_punish_level: 2<br \/>\n&#8220;`<\/p>\n<p>&#8212;<\/p>\n<p>## \ud83d\udd25 Firewall mode setup<\/p>\n<p>Firewall mode executes an OS script asynchronously. To enable it:<\/p>\n<p>&#8220;`yaml<br \/>\nauto_punishment:<br \/>\n  command: &#8220;firewall&#8221;<br \/>\n  allow_unsafe_firewall_exec: true<br \/>\n  firewall_timeout_seconds: 10<br \/>\n  # Linux:<br \/>\n  firewall_script: &#8220;iptables -A INPUT -s {ip} -j DROP&#8221;<br \/>\n  # Windows:<br \/>\n  # firewall_script: &#8220;netsh advfirewall firewall add rule name=OPShield dir=in action=block remoteip={ip}&#8221;<br \/>\n&#8220;`<\/p>\n<p>If `allow_unsafe_firewall_exec` is `false`, firewall mode falls back to a safe kick.<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udd0d Troubleshooting<\/p>\n<details>\n<summary><b>Cannot use \/op \u2014 &#8220;Incorrect password&#8221;<\/b><\/summary>\n<p>The password is required. Run:<br \/>\n&#8220;`<br \/>\n\/op <yourname> <password>\n&#8220;`<br \/>\nIf you forgot the password, clear `op_password_hash` in `config.yml` and restart \u2014 a new password will be generated and printed in the console.<br \/>\n<\/details>\n<details>\n<summary><b>Player is locked out and cannot try again<\/b><\/summary>\n<p>An admin can manually clear the lockout:<br \/>\n&#8220;`<br \/>\n\/opshield unlock <playername>\n\/opshield unlock <ip-address><br \/>\n&#8220;`<br \/>\n<\/details>\n<details>\n<summary><b>Auto-punishment is not triggering<\/b><\/summary>\n<p>Check the following:<br \/>\n&#8211; `auto_punishment.enabled: true` in `config.yml`<br \/>\n&#8211; The command the player used is listed in `auto_punishment.sensitive_commands`<br \/>\n&#8211; `shadow_ban.enabled` \u2014 if true, the player may be getting fake success messages instead<br \/>\n&#8211; Run `\/opshield reload` after any config change<br \/>\n<\/details>\n<details>\n<summary><b>Audit log is empty or not updating<\/b><\/summary>\n<p>&#8211; Check `audit.console_output: true` to confirm logging is active<br \/>\n&#8211; Check write permissions on the `plugins\/OPShield\/` folder<br \/>\n&#8211; In 1.6.0, failed writes are retried and logged to console as `SEVERE` \u2014 check console output<br \/>\n<\/details>\n<details>\n<summary><b>Config changes are not taking effect<\/b><\/summary>\n<p>Run in-game or console:<br \/>\n&#8220;`<br \/>\n\/opshield reload<br \/>\n&#8220;`<br \/>\n<\/details>\n<p>&#8212;<\/p>\n<p># \u2753 FAQ<\/p>\n<p>### Does OPShield replace `\/op`?<br \/>\nNo \u2014 it intercepts and wraps it. The original `\/op` behaviour is preserved but gated behind a password.<\/p>\n<p>&#8212;<\/p>\n<p>### Is the password stored securely?<br \/>\nYes \u2014 passwords are hashed using PBKDF2-HMAC-SHA256 with a random salt and 120,000 iterations (configurable). The plaintext is never written to disk.<\/p>\n<p>&#8212;<\/p>\n<p>### Does it support Spigot or Folia?<br \/>\nPaper 1.21+ only. Spigot may work but is not tested. Folia is explicitly **not supported** (`folia-supported: false`).<\/p>\n<p>&#8212;<\/p>\n<p>### Can I disable auto-punishment entirely?<br \/>\nYes \u2014 set `auto_punishment.enabled: false`. Shadow-ban fake messages will still work independently.<\/p>\n<p>&#8212;<\/p>\n<p>### What happens if the server restarts during a lockout?<br \/>\nLockout state is persisted to `data.yml` and restored on startup. Players cannot bypass lockouts by crashing or restarting the server.<\/p>\n<p>&#8212;<\/p>\n<p>### Can I have multiple language files?<br \/>\nYes \u2014 all three bundled files (`en`, `vn`, `ru`) are always present. Switch via `language:` in `config.yml`. Missing keys automatically fall back to the bundled English defaults.<\/p>\n<p>&#8212;<\/p>\n<p># \ud83d\udcc4 Credits<\/p>\n<p>**Author:** Duong2012G<br \/>\n**License:** Apache 2.0<br \/>\n**Website:** https:\/\/modrinth.com\/user\/Duong2012G<\/p>\n<p>*Built for secure, professional Minecraft servers.*<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Protects your server from OP\/admin abuse with console-only OP (via password) and optional admin command restriction.<\/p>\n","protected":false},"featured_media":116532,"template":"","meta":{"_minecraft_slug":"opshield","_minecraft_project_id":"Bv67n40d","_minecraft_author":"Duong2012G","_minecraft_license":"Apache-2.0","_minecraft_downloads":126,"_minecraft_follows":1,"_minecraft_client_side":"unsupported","_minecraft_server_side":"required","_minecraft_storage_type":"zip","_minecraft_archive_name":"opshield.zip","_minecraft_size_bytes":313347,"_minecraft_version_count":13,"_minecraft_updated_at":"2026-05-15T19:18:28.885989Z","_minecraft_date_created":"2026-03-11T23:13:21.779083Z","_minecraft_date_modified":"2026-05-15T23:50:32.684537Z","_minecraft_project_url":"https:\/\/modrinth.com\/mod\/opshield","_minecraft_icon_attachment_id":116532,"_minecraft_imported_at":"2026-06-06T20:35:49+00:00","_minecraft_import_hash":"c114ca455fb3921ddde59ef99407cd14","_minecraft_versions":"","_minecraft_links":"","_minecraft_gallery":"","_minecraft_api_metadata":""},"mod_category":[87,124,43,126,127,128,129],"mod_loader":[130,132,133,134],"minecraft_version":[62,37,40,41,73,74,38,78,79,80,81,82],"class_list":["post-116531","mod","type-mod","status-publish","has-post-thumbnail","hentry","mod_category-adventure","mod_category-bukkit","mod_category-cursed","mod_category-management","mod_category-paper","mod_category-purpur","mod_category-spigot","mod_loader-bukkit","mod_loader-paper","mod_loader-purpur","mod_loader-spigot","minecraft_version-1-21","minecraft_version-1-21-1","minecraft_version-1-21-10","minecraft_version-1-21-11","minecraft_version-1-21-2","minecraft_version-1-21-3","minecraft_version-1-21-4","minecraft_version-1-21-5","minecraft_version-1-21-6","minecraft_version-1-21-7","minecraft_version-1-21-8","minecraft_version-1-21-9"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>OPShield - Minecraft<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"OPShield - Minecraft\" \/>\n<meta property=\"og:description\" content=\"Protects your server from OP\/admin abuse with console-only OP (via password) and optional admin command restriction.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/\" \/>\n<meta property=\"og:site_name\" content=\"Minecraft\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/opshield\\\/\",\"url\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/opshield\\\/\",\"name\":\"OPShield - Minecraft\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/opshield\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/opshield\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/opshield-icon-8e8db8948461db1f2f46d24a17daf4eff2c9c9d6_96.webp\",\"datePublished\":\"2026-06-06T20:35:48+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/opshield\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/opshield\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/opshield\\\/#primaryimage\",\"url\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/opshield-icon-8e8db8948461db1f2f46d24a17daf4eff2c9c9d6_96.webp\",\"contentUrl\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/opshield-icon-8e8db8948461db1f2f46d24a17daf4eff2c9c9d6_96.webp\",\"width\":96,\"height\":96},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/opshield\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Mods\",\"item\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/mods\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"OPShield\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/#website\",\"url\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/\",\"name\":\"Minecraft\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/vpesports.com\\\/minecraft\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"OPShield - Minecraft","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/","og_locale":"en_US","og_type":"article","og_title":"OPShield - Minecraft","og_description":"Protects your server from OP\/admin abuse with console-only OP (via password) and optional admin command restriction.","og_url":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/","og_site_name":"Minecraft","twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/","url":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/","name":"OPShield - Minecraft","isPartOf":{"@id":"https:\/\/vpesports.com\/minecraft\/#website"},"primaryImageOfPage":{"@id":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/#primaryimage"},"image":{"@id":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/#primaryimage"},"thumbnailUrl":"https:\/\/vpesports.com\/minecraft\/wp-content\/uploads\/2026\/06\/opshield-icon-8e8db8948461db1f2f46d24a17daf4eff2c9c9d6_96.webp","datePublished":"2026-06-06T20:35:48+00:00","breadcrumb":{"@id":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/vpesports.com\/minecraft\/mods\/opshield\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/#primaryimage","url":"https:\/\/vpesports.com\/minecraft\/wp-content\/uploads\/2026\/06\/opshield-icon-8e8db8948461db1f2f46d24a17daf4eff2c9c9d6_96.webp","contentUrl":"https:\/\/vpesports.com\/minecraft\/wp-content\/uploads\/2026\/06\/opshield-icon-8e8db8948461db1f2f46d24a17daf4eff2c9c9d6_96.webp","width":96,"height":96},{"@type":"BreadcrumbList","@id":"https:\/\/vpesports.com\/minecraft\/mods\/opshield\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/vpesports.com\/minecraft\/"},{"@type":"ListItem","position":2,"name":"Mods","item":"https:\/\/vpesports.com\/minecraft\/mods\/"},{"@type":"ListItem","position":3,"name":"OPShield"}]},{"@type":"WebSite","@id":"https:\/\/vpesports.com\/minecraft\/#website","url":"https:\/\/vpesports.com\/minecraft\/","name":"Minecraft","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/vpesports.com\/minecraft\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"}]}},"_links":{"self":[{"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/mod\/116531","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/mod"}],"about":[{"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/types\/mod"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/media\/116532"}],"wp:attachment":[{"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/media?parent=116531"}],"wp:term":[{"taxonomy":"mod_category","embeddable":true,"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/mod_category?post=116531"},{"taxonomy":"mod_loader","embeddable":true,"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/mod_loader?post=116531"},{"taxonomy":"minecraft_version","embeddable":true,"href":"https:\/\/vpesports.com\/minecraft\/wp-json\/wp\/v2\/minecraft_version?post=116531"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}