📖 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
- 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: English (
en), Vietnamese (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
- UTF-8 safe — 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
- Download the plugin
.jar
- Drop it into your server's
plugins/ folder
- Start the server — OPShield will generate a random password and print it once in the console
- Save the password somewhere safe (it is only shown once)
- Open
plugins/OPShield/config.yml to customise behaviour
- 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
# 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)
security.lockout.max-attempts: 3
security.lockout.duration-minutes: 5
ip_limit.max_accounts: 2
auto_punishment.enabled: false
Medium server (20–100 players)
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)
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:
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
<details>
<summary>Cannot use /op — "Incorrect password"</summary>
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.
</details>
<details>
<summary>Player is locked out and cannot try again</summary>
An admin can manually clear the lockout:
/opshield unlock <playername>
/opshield unlock <ip-address>
</details>
<details>
<summary>Auto-punishment is not triggering</summary>
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
</details>
<details>
<summary>Audit log is empty or not updating</summary>
- 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
</details>
<details>
<summary>Config changes are not taking effect</summary>
Run in-game or console:
/opshield reload
</details>
❓ 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
Author: Duong2012G
License: Apache 2.0
Website: https://legacy.curseforge.com/members/duong2012g/projects
Built for secure, professional Minecraft servers.