OPShield
Protects your server from OP/admin abuse with console-only OP (via password) and optional admin command restriction.
Quick challenge
How far can you run before the mobs catch you?
Minecraft check
Confirm your run
Complete the quick check to get your code.
OPShield
🛡️ OPShield
Advanced security & command protection plugin for Paper 1.21+
[]() [
]() [
]() [
]()
*Protect your server from abuse — secure OP access, track every action, stop attackers instantly.*
---
📖 Table of Contents
- ✨ Features - 🔐 Security System - 📊 Audit & Logging - 📦 Requirements - 🚀 Installation - ⌨️ Commands & Permissions - 🔧 Configuration - 🔍 Troubleshooting - ❓ FAQ - 📄 Credits
---
✨ Features
🔒 OP Protection
- Password-gated `/op` and `/deop` — no password, no privilege changes - PBKDF2-HMAC-SHA256 hashed storage — plaintext never kept in config - Configurable PBKDF2 iteration count (`security.password.pbkdf2_iterations`) - Automatic migration from legacy plaintext and SHA-256 hashes - Auto-upgrade legacy hashes — on next successful login, SHA-256 is silently replaced with PBKDF2 (`security.password.auto_upgrade_legacy_hash`) - Console warning if a legacy SHA-256 hash is detected on startup - OP whitelist — restrict `/op` to a predefined set of player names
---
🚫 Sensitive Command Protection
- Block dangerous commands for non-OP players (`blocked_commands`) - Optionally block commands even for OP players (`blocked_op_commands`) - Block entire command namespaces via prefix list (`blocked_command_prefixes`) - Alias and namespace resolution — bypass attempts via `minecraft:op` or plugin aliases are caught - Per-player bypass permission (`opshield.bypass`) for trusted staff
---
🧠 Brute-force Detection & Lockout
- Configurable failed-attempt limit before lockout (`security.lockout.max-attempts`) - Exponential backoff — each offence doubles the lockout duration - Optional IP-mirrored lockout (`security.lockout.track_ip`) - Lockout count decay after a cooling-off period (`security.lockout.count_decay_hours`) - Persistent tracking — lockout state survives server restarts - Manual unlock via `/opshield unlock <player|ip>`
---
🕵️ Shadow Ban System
- Sensitive blocked commands send a fake success message instead of an error - Each trigger increments the player's hidden shadow-ban level - Level persists across restarts - Auto-escalates to real punishment when `shadow_ban.auto_punish_level` is reached - Set `auto_punish_level: 99` to keep decoy behaviour without escalation - Fake messages come from language files — fully customisable per locale
---
⚠️ Auto Punishment System
- Punishment modes: `kick`, `ban`, `ban-ip`, `firewall`, `custom` - Persistent rolling-window threshold — survives restarts and crashes - Firewall mode runs an OS script asynchronously via `ProcessBuilder` with configurable timeout - Custom mode supports `{player}` and `{ip}` placeholders - IP-limit auto-punishment for accounts detected sharing the same IP
---
🌍 Multi-Language Support
- Bundled language files: Russian (`en`), Russian (`vn`), Russian (`ru`) - Automatic fallback to English for any missing key - Switch language via `language: "en"` in `config.yml`
---
📊 Audit & Logging
- Every privilege change, password failure, command block, and punishment is logged - Async queue — log writes never touch the main thread - Retry on failure — `audit.max_queue_size` prevents OOM if disk writes fail for extended periods - Retry on failure — `audit.format: plain` (default human-readable) or `audit.format: json` (machine-readable, one JSON object per line) - Retry on failure — uses NIO `Files.write()` with explicit charset - Retry on failure — failed writes are re-queued instead of silently discarded - Configurable rotation: `audit.max_file_size_mb` and `audit.log_retention` (up to N backup files) - Optional console mirror: `audit.console_output: true` - Log files: `plugins/OPShield/audit.log`, `audit.log.1` … `audit.log.N`
---
📦 Requirements
| Component | Version | |-----------|---------| | Java | 21+ | | Paper | 1.21+ | | Folia | ❌ Not supported |
---
🚀 Installation
1. Download the plugin `.jar` 2. Drop it into your server's `plugins/` folder 3. Start the server — OPShield will generate a random password and print it Grant permissions in the console 4. Save the password somewhere safe (it is only shown once) 5. Grant permissions — 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) 6. Open `plugins/OPShield/config.yml` to customise behaviour 7. Run `/opshield reload` in-game or restart to apply changes ✅
> Upgrading from 1.7.0? `data.yml` is automatically migrated on first boot. You only need to update your permission plugin setup — see the CRITICAL note in the changelog.
> Tip: If you already have an `op_password` plaintext value from an older version, > OPShield will automatically migrate it to `op_password_hash` and remove the plaintext entry.
---
⌨️ Commands
| Command | Description | |---------|-------------| | `/op <player> [password]` | Grant OP with password verification | | `/deop <player> [password]` | Remove OP with password verification | | `/opshield reload` | Reload configuration | | `/opshield unlock <player|ip>` | Clear all tracking state for a player or IP | | `/opshield status` | Show runtime statistics (active levels, flagged IPs, etc.) |
---
🔐 Permissions
> ⚠️ Changed in v1.8.0: All permissions now default to `false`. You must grant them explicitly via a permission plugin.
| Permission | Default | Description | |------------|---------|-------------| | `opshield.*` | false | Wildcard — grants all permissions | | `opshield.admin` | false | Grants all child permissions | | `opshield.reload` | false | Reload OPShield configuration | | `opshield.unlock` | false | Unlock a tracked player or IP | | `opshield.status` | false | View runtime statistics | | `opshield.op` | false | Use password-protected `/op` | | `opshield.deop` | false | Use password-protected `/deop` | | `opshield.bypass` | false | Bypass non-OP restricted command blocking |
Example LuckPerms setup
```bash /lp group admin permission set opshield.admin true ```
---
🔧 Configuration
Files generated under `plugins/OPShield/`:
- `config.yml` — main configuration - `data.yml` — persistent runtime state (lockouts, shadow-ban levels, IP windows) - `languages/en.yml` — English messages - `languages/vn.yml` — Vietnamese messages - `languages/ru.yml` — Russian messages
---
⚙️ Key Config Options
```yaml
Enable verbose console logging for troubleshooting (disable in production)
debug: false
Password security
security: lockout: enabled: true max-attempts: 3 duration-minutes: 3 track_ip: true count_decay_hours: 168 password: pbkdf2_iterations: 120000 # range: 10000 – 1000000 auto_upgrade_legacy_hash: true # silently upgrade SHA-256 → PBKDF2 on login
Auto-punishment
auto_punishment: enabled: true threshold: 5 window_seconds: 300 command: "kick" # kick | ban | ban-ip | firewall | custom firewall_timeout_seconds: 10
Shadow ban
shadow_ban: enabled: true auto_punish_level: 5
Audit log
audit: console_output: true max_file_size_mb: 5 log_retention: 3 max_queue_size: 10000 # 0 = unlimited (not recommended) format: "plain" # plain | json ```
---
📐 Recommended settings by server size
Small server (≤ 20 players) ```yaml security.lockout.max-attempts: 3 security.lockout.duration-minutes: 5 ip_limit.max_accounts: 2 auto_punishment.enabled: false shadow_ban.auto_punish_level: 10 ```
Medium server (20–100 players) ```yaml security.lockout.max-attempts: 3 security.lockout.duration-minutes: 3 ip_limit.max_accounts: 3 auto_punishment.enabled: true auto_punishment.command: kick auto_punishment.threshold: 5 shadow_ban.auto_punish_level: 5 ```
Large server (100+ players) ```yaml security.lockout.max-attempts: 2 security.lockout.duration-minutes: 10 ip_limit.max_accounts: 2 auto_punishment.enabled: true auto_punishment.command: ban-ip auto_punishment.threshold: 3 shadow_ban.auto_punish_level: 3 ```
---
🔥 Firewall mode setup
Firewall mode executes an OS script asynchronously. To enable it:
```yaml auto_punishment: command: "firewall" allow_unsafe_firewall_exec: true firewall_timeout_seconds: 10
Linux:
firewall_script: "iptables -A INPUT -s {ip} -j DROP"
Windows:
firewall_script: "netsh advfirewall firewall add rule name=OPShield dir=in action=block remoteip={ip}"
```
If `allow_unsafe_firewall_exec` is `false`, firewall mode falls back to a safe kick.
---
🔍 Troubleshooting
Cannot use /op — "Incorrect password"
The password is required. Run: ``` /op <yourname> <password> ``` If you forgot the password, clear `op_password_hash` in `config.yml` and restart — a new password will be generated and printed in the console.
Admin cannot use /opshield after upgrading from 1.7.0
In v1.8.0, permissions now default to `false` instead of `op`. You need to explicitly grant the permission: ```bash /lp group admin permission set opshield.admin true ```
Player is locked out and cannot try again
An admin can manually clear the lockout: ``` /opshield unlock <playername> /opshield unlock <ip-address> ```
Auto-punishment is not triggering
Check the following: - `auto_punishment.enabled: true` in `config.yml` - The command the player used is listed in `auto_punishment.sensitive_commands` - `shadow_ban.enabled` — if true, the player may be getting fake success messages first; level must reach `auto_punish_level` - Run `/opshield reload` after any config change - Run `/opshield status` to see current shadow-ban levels and punish state
Audit log is empty or not updating
- Check `audit.console_output: true` to confirm logging is active - Check write permissions on the `plugins/OPShield/` folder - If `audit.max_queue_size` is reached, a `SEVERE` warning appears in console — check disk space
Config changes are not taking effect
Run in-game or console: ``` /opshield reload ```
---
❓ FAQ
Does OPShield replace `/op`?
No — it intercepts and wraps it. The original `/op` behaviour is preserved but gated behind a password.
---
Is the password stored securely?
Yes — passwords are hashed using PBKDF2-HMAC-SHA256 with a random salt and 120,000 iterations (configurable). The plaintext is never written to disk.
---
Does it support Spigot or Folia?
Paper 1.21+ only. Spigot may work but is not tested. Folia is explicitly not supported (`folia-supported: false`).
---
Can I disable auto-punishment entirely?
Yes — set `auto_punishment.enabled: false`. Shadow-ban fake messages will still work independently.
---
What happens if the server restarts during a lockout?
Lockout state is persisted to `data.yml` and restored on startup. Players cannot bypass lockouts by crashing or restarting the server.
---
Can I have multiple language files?
Yes — 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.
---
What changed in v1.8.0?
The most important change is permission defaults — see the permission defaults for the full list. The short version: grant `opshield.admin` to your admin group in LuckPerms.
---
📄 Credits
Website: Duong2012G Website: Apache 2.0 Website: https://modrinth.com/user/Duong2012G
*Built for secure, professional Minecraft servers.* - Password-gated `/op` and `/deop` — no password, no privilege changes - PBKDF2-HMAC-SHA256 hashed storage — plaintext never kept in config - Configurable PBKDF2 iteration count (`security.password.pbkdf2_iterations`) - Automatic migration from legacy plaintext and SHA-256 hashes - Console warning if a legacy SHA-256 hash is detected on startup - OP whitelist — restrict `/op` to a predefined set of player names
---
🚫 Sensitive Command Protection
- Block dangerous commands for non-OP players (`blocked_commands`) - Optionally block commands even for OP players (`blocked_op_commands`) - Block entire command namespaces via prefix list (`blocked_command_prefixes`) - Alias and namespace resolution — bypass attempts via `minecraft:op` or plugin aliases are caught - Per-player bypass permission (`opshield.bypass`) for trusted staff
---
🧠 Brute-force Detection & Lockout
- Configurable failed-attempt limit before lockout (`security.lockout.max-attempts`) - Exponential backoff — each offence doubles the lockout duration - Optional IP-mirrored lockout (`security.lockout.track_ip`) - Lockout count decay after a cooling-off period (`security.lockout.count_decay_hours`) - Persistent tracking — lockout state survives server restarts - Manual unlock via `/opshield unlock <player|ip>`
---
🕵️ Shadow Ban System
- Sensitive blocked commands send a fake success message instead of an error - Each trigger increments the player's hidden shadow-ban level - Level persists across restarts - Auto-escalates to real punishment when `shadow_ban.auto_punish_level` is reached - Set `auto_punish_level: 99` to keep decoy behaviour without escalation
---
⚠️ Auto Punishment System
- Punishment modes: `kick`, `ban`, `ban-ip`, `firewall`, `custom` - Persistent rolling-window threshold — survives restarts and crashes - Firewall mode runs an OS script asynchronously via `ProcessBuilder` with configurable timeout - Custom mode supports `{player}` and `{ip}` placeholders - IP-limit auto-punishment for accounts detected sharing the same IP
---
🌍 Multi-Language Support
- Bundled language files: Russian (`en`), Russian (`vn`), Russian (`ru`) - Automatic fallback to English for any missing key - Switch language via `language: "en"` in `config.yml`
---
📊 Audit & Logging
- Every privilege change, password failure, command block, and punishment is logged - Async queue — log writes never touch the main thread - Retry on failure — uses NIO `Files.write()` with explicit charset (fixed in 1.6.0) - Retry on failure — failed writes are re-queued instead of silently discarded (fixed in 1.6.0) - Configurable rotation: `audit.max_file_size_mb` and `audit.log_retention` (up to N backup files) - Optional console mirror: `audit.console_output: true` - Log files: `plugins/OPShield/audit.log`, `audit.log.1` … `audit.log.N`
---
📦 Requirements
| Component | Version | |-----------|---------| | Java | 21+ | | Paper | 1.21+ | | Folia | ❌ Not supported |
---
🚀 Installation
1. Download the plugin `.jar` 2. Drop it into your server's `plugins/` folder 3. Start the server — OPShield will generate a random password and print it once in the console 4. Save the password somewhere safe (it is only shown once) 5. Open `plugins/OPShield/config.yml` to customise behaviour 6. Run `/opshield reload` in-game or restart to apply changes ✅
> Tip: If you already have an `op_password` plaintext value from an older version, > OPShield will automatically migrate it to `op_password_hash` and remove the plaintext entry.
---
⌨️ Commands
| Command | Description | |---------|-------------| | `/op <player> [password]` | Grant OP with password verification | | `/deop <player> [password]` | Remove OP with password verification | | `/opshield reload` | Reload configuration | | `/opshield unlock <player|ip>` | Clear all tracking state for a player or IP |
---
🔐 Permissions
| Permission | Default | Description | |------------|---------|-------------| | `opshield.admin` | op | Grants all child permissions | | `opshield.reload` | op | Reload OPShield configuration | | `opshield.unlock` | op | Unlock a tracked player or IP | | `opshield.op` | op | Use password-protected `/op` | | `opshield.deop` | op | Use password-protected `/deop` | | `opshield.bypass` | false | Bypass non-OP restricted command blocking |
---
🔧 Configuration
Files generated under `plugins/OPShield/`:
- `config.yml` — main configuration - `data.yml` — persistent runtime state (lockouts, shadow-ban levels, IP windows) - `languages/en.yml` — English messages - `languages/vn.yml` — Vietnamese messages - `languages/ru.yml` — Russian messages
---
⚙️ Example Config
```yaml
Password security
security: lockout: enabled: true max-attempts: 3 duration-minutes: 3 track_ip: true count_decay_hours: 168 password: pbkdf2_iterations: 120000 # range: 10000 – 1000000
Auto-punishment
auto_punishment: enabled: true threshold: 5 window_seconds: 300 command: "kick" # kick | ban | ban-ip | firewall | custom firewall_timeout_seconds: 10
Shadow ban
shadow_ban: enabled: true auto_punish_level: 3
Audit log
audit: console_output: true max_file_size_mb: 5 log_retention: 3 ```
---
📐 Recommended settings by server size
Small server (≤ 20 players) ```yaml security.lockout.max-attempts: 3 security.lockout.duration-minutes: 5 ip_limit.max_accounts: 2 auto_punishment.enabled: false ```
Medium server (20–100 players) ```yaml security.lockout.max-attempts: 3 security.lockout.duration-minutes: 3 ip_limit.max_accounts: 3 auto_punishment.enabled: true auto_punishment.command: kick auto_punishment.threshold: 5 shadow_ban.auto_punish_level: 3 ```
Large server (100+ players) ```yaml security.lockout.max-attempts: 2 security.lockout.duration-minutes: 10 ip_limit.max_accounts: 2 auto_punishment.enabled: true auto_punishment.command: ban-ip auto_punishment.threshold: 3 shadow_ban.auto_punish_level: 2 ```
---
🔥 Firewall mode setup
Firewall mode executes an OS script asynchronously. To enable it:
```yaml auto_punishment: command: "firewall" allow_unsafe_firewall_exec: true firewall_timeout_seconds: 10
Linux:
firewall_script: "iptables -A INPUT -s {ip} -j DROP"
Windows:
firewall_script: "netsh advfirewall firewall add rule name=OPShield dir=in action=block remoteip={ip}"
```
If `allow_unsafe_firewall_exec` is `false`, firewall mode falls back to a safe kick.
---
🔍 Troubleshooting
Cannot use /op — "Incorrect password"
The password is required. Run: ``` /op <yourname> <password> ``` If you forgot the password, clear `op_password_hash` in `config.yml` and restart — a new password will be generated and printed in the console.
Player is locked out and cannot try again
An admin can manually clear the lockout: ``` /opshield unlock <playername> /opshield unlock <ip-address> ```
Auto-punishment is not triggering
Check the following: - `auto_punishment.enabled: true` in `config.yml` - The command the player used is listed in `auto_punishment.sensitive_commands` - `shadow_ban.enabled` — if true, the player may be getting fake success messages instead - Run `/opshield reload` after any config change
Audit log is empty or not updating
- Check `audit.console_output: true` to confirm logging is active - Check write permissions on the `plugins/OPShield/` folder - In 1.6.0, failed writes are retried and logged to console as `SEVERE` — check console output
Config changes are not taking effect
Run in-game or console: ``` /opshield reload ```
---
❓ FAQ
Does OPShield replace `/op`?
No — it intercepts and wraps it. The original `/op` behaviour is preserved but gated behind a password.
---
Is the password stored securely?
Yes — passwords are hashed using PBKDF2-HMAC-SHA256 with a random salt and 120,000 iterations (configurable). The plaintext is never written to disk.
---
Does it support Spigot or Folia?
Paper 1.21+ only. Spigot may work but is not tested. Folia is explicitly not supported (`folia-supported: false`).
---
Can I disable auto-punishment entirely?
Yes — set `auto_punishment.enabled: false`. Shadow-ban fake messages will still work independently.
---
What happens if the server restarts during a lockout?
Lockout state is persisted to `data.yml` and restored on startup. Players cannot bypass lockouts by crashing or restarting the server.
---
Can I have multiple language files?
Yes — 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.
---
📄 Credits
Website: Duong2012G Website: Apache 2.0 Website: https://modrinth.com/user/Duong2012G
*Built for secure, professional Minecraft servers.*