Compatibility
Minecraft: Java Edition
Platforms
Tags
Creators
Details
š”ļø 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
/opand/deopā no password, no privilege changes - Async PBKDF2 verification ā password hashing runs off the main thread; zero TPS impact even under brute-force attack
- Authenticated session tokens ā after one successful login, a configurable session window lets admins skip re-entering the password (
security.session_timeout_minutes, default 30 min) - Session cleared on disconnect ā sessions are never carried across reconnections
- Global auth concurrency cap ā server-wide PBKDF2 operations capped at 4 concurrent verifications to prevent CPU saturation under mass attack
- 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
/opto 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:opor 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_levelis reached - Set
auto_punish_level: 99to 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
ProcessBuilderwith 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"inconfig.yml
š Audit & Logging
- Every privilege change, password failure, command block, and punishment is logged
- Async queue ā log writes never touch the main thread
- Queue capacity limit ā
audit.max_queue_sizeprevents OOM if disk writes fail for extended periods - Dual output format ā
audit.format: plain(default human-readable) oraudit.format: json(machine-readable, one JSON object per line) - UTF-8 safe ā 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_mbandaudit.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)
- Grant permissions ā add
opshield.adminto 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) - Open
plugins/OPShield/config.ymlto customise behaviour - Run
/opshield reloadin-game or restart to apply changes ā
Upgrading from 1.7.0?
data.ymlis 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_passwordplaintext value from an older version, OPShield will automatically migrate it toop_password_hashand 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 sessions, auth queue, 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
/lp group admin permission set opshield.admin true
š§ Configuration
Files generated under plugins/OPShield/:
config.ymlā main configurationdata.ymlā persistent runtime state (lockouts, shadow-ban levels, IP windows)languages/en.ymlā English messageslanguages/vn.ymlā Vietnamese messageslanguages/ru.ymlā Russian messages
āļø Key Config Options
# 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
# Session timeout after successful auth (0 = disable, always require password)
session_timeout_minutes: 30
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)
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)
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)
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:
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
Admin needs to enter password every single /op command
OPShield grants a session after each successful authentication. Check:
security.session_timeout_minutesinconfig.ymlā if set to0, sessions are disabled- The session is cleared when you disconnect; if you keep reconnecting you will need to re-authenticate
- Run
/opshield statusto see how many active sessions exist
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:
/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: trueinconfig.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 reachauto_punish_level- Run
/opshield reloadafter any config change - Run
/opshield statusto see current shadow-ban levels and punish state
Audit log is empty or not updating
- Check
audit.console_output: trueto confirm logging is active - Check write permissions on the
plugins/OPShield/folder - If
audit.max_queue_sizeis reached, aSEVEREwarning 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 v2.0.0?
Thread-safety overhaul ā five race conditions and visibility bugs fixed:
ArrayDequerace condition ā replaced withConcurrentLinkedDequeto preventConcurrentModificationExceptionand data corruption when the async cleanup task and main-thread event handler accessed the same deque simultaneously.- Non-volatile config fields ā
lockoutDecayHours,autoPunishmentWindowSeconds,ipLimitTimeWindowSeconds, andsessionTimeoutMsare nowvolatileso async tasks always see up-to-date values after/opshield reload. - Non-volatile
AuditLoggerfields āconsoleOutput,maxBytes,maxBackups,maxQueueSize, andformatare nowvolatile. - IP range check ā replaced 16 manual
startsWith()checks withInetAddresspredicates, adding previously missing link-local range detection. - Audit log level ā audit console output now uses
INFOinstead ofWARNING.
See the Changelog for details.
What changed in v1.9.1?
Six bugs fixed in a patch release: double timestamps in audit log, missing session-granted/active messages, shadow-ban decoy messages losing their colours, exponential backoff count being reset too early (making count_decay_hours ineffective), and the /opshield reload permission check order. See the Changelog for details.
What changed in v1.9.0?
The biggest changes are async PBKDF2 authentication (no more TPS impact under brute-force) and session tokens (no need to re-type the password every command within the session window). See the Changelog for the full list.
What changed in v1.8.0?
The most important change is permission defaults ā see the Changelog for the full list. The short version: grant opshield.admin to your admin group in LuckPerms.
š Credits
Author: Duong2012G
License: Apache 2.0
Website: https://modrinth.com/user/Duong2012G
Built for secure, professional Minecraft servers.


