This document describes the security boundary of the KarixMC website and KarixMCBridge 0.6.6. It is a technical operating guide, not a promise that any internet service can be made bug-free.
- The KarixMC website and database are authoritative for wallets, campaign pools, reward rates, paid-player caps, challenges, store prices, purchases, premium state, reports, and enforcement.
- A Server ID is a public identifier used to route requests. It is not a password.
- A plugin secret is a private signing key. It is shown once, encrypted at rest with AES-256-GCM, and can be rotated. The old key stops working immediately after rotation.
- Every protocol-v2 plugin request and response uses HMAC-SHA256 over the HTTP method or response status, path, Server ID, timestamp, one-time nonce, and exact body hash.
- The website rejects stale timestamps, duplicate nonces, altered bodies, invalid signatures, inactive servers, suspended servers, blacklisted servers, oversized messages, and excessive request rates.
- Browser state changes are protected by strict Origin/Referer and Fetch Metadata checks at the Next.js proxy. Plugin requests remain separate and require protocol-v2 signatures.
- Nginx replaces
X-Real-IPfrom the actual TCP peer. Application throttles ignore client-supplied Cloudflare and forwarded-IP headers unless the deployment is deliberately moved behind a configured trusted proxy. - Each community account can publish one current server address. A partial unique database index enforces the limit during concurrent requests; official platform-operated showcases are exempt.
- A short, atomic per-player lease permits rewards from only one server at a time. Optimistic heartbeat writes and a unique active-session index stop concurrent requests from crediting the same elapsed interval twice.
Unlinked players are not included in reward heartbeat batches. Running /karixmc link <code> opts that Minecraft identity into the limited activity data needed for KarixMC rewards on that server.
The plugin sends:
- linked Minecraft UUID and current Minecraft name;
- active/AFK state;
- bounded movement and interaction counters;
- a bounded elapsed-time claim;
- activity-check ID and answer when submitted;
- plugin version once per batch.
The plugin does not read or transmit a Minecraft player's IP address. Reward sessions do not have an IP-address or IP-hash column. /karixmc privacy explains the current state in game. /karixmc forget removes the local opt-in and stops future reward heartbeats for that player on that server.
The website separately uses a one-way connection fingerprint for login abuse prevention. That is website authentication traffic, not Minecraft player telemetry.
A server owner controls the machine running Paper and can replace or modify any plugin. Cryptographic signatures prove that a request used the configured secret and was not altered in transit; they cannot prove that owner-controlled software reported honest physical gameplay.
KarixMC contains this risk by calculating money and challenge state on the website, limiting elapsed time to website-observed wall time, enforcing paid-player caps and campaign deductions atomically, recording nonce history, bounding activity values, providing player reports, tracking trust state, and allowing administrators to pause or blacklist a server. Production fraud controls should also compare server behavior over time and send high-risk cases to human review.
- Bounded batches are sent per heartbeat cycle instead of one request per player; populations over 200 are split into sequential chunks.
- Heartbeat batches contain at most 250 unique players and 256 KiB of JSON.
- Other plugin requests are capped at 64 KiB.
- Java HTTP responses are capped before full allocation.
- Network work runs asynchronously and Bukkit calls return to the server thread.
- In-flight request guards, cooldowns, finite timeouts, counter clamps, expired-challenge cleanup, and plugin shutdown cleanup prevent unbounded queues and stale references.
- Repeated network errors are throttled instead of printed on every tick.
- Public package quantities and prices remain database-managed; the website formats those existing cent values as EUR.
- Discord messages, receipts, and screenshots are untrusted coordination material. An administrator grants a paid order only after independently seeing the settled transfer in the beneficiary bank account.
- The manual campaign form presents active database packages and sends the selected point amount through the existing administrator-only grant endpoint. Premium is granted for the requested 14-day Gold or Diamond period.
- The website does not receive, initiate, or automatically confirm a bank payment. Operators must maintain a separate reconciliation log and must not fulfill the same transfer twice.
- Administrative grant ledgers record the affected account or server and the operator-entered reason.
- Staff never request passwords, TOTP codes, plugin secrets, bank logins, card details, or private keys.
- Region and Minecraft version use controlled values; a listing stores minimum and maximum supported versions.
- Profile and gallery images must be uploaded. Remote media URLs are rejected to prevent third-party tracking, unsafe content embedding, and protocol abuse.
- Uploaded PNG/JPEG files are decoded and re-encoded with metadata removed, pixel and byte limits, and generated local filenames.
- Media uploads have a persistent per-account request throttle and a hard per-account file and storage quota.
- Store commands reject control characters and leading slashes, must include
{player}or{uuid}, and permit only those placeholders. - Point purchases use an atomic sufficient-balance update, so simultaneous purchases cannot spend the same wallet balance twice.
- Public output is rendered through React escaping and protected by a restrictive Content Security Policy, frame denial, MIME sniffing protection, and a referrer policy.
- Executable scripts require a fresh per-response CSP nonce; production
script-srcdoes not allow arbitrary inline scripts or eval.
The official showcase temporarily accepts offline/non-premium Java clients. AuthMe therefore owns the player-name authentication boundary: a Minecraft name is not trustworthy until that exact name has completed AuthMe registration and login. The three official worlds share one private AuthMe database, so players register once and use /login on the other worlds.
Never grant operator permissions, privileged groups, or allowlisted status to an unregistered offline-mode name. An attacker could otherwise claim the name first and inherit its privileges. The showcase monitor checks every operator name against the shared AuthMe registration table.
- Open Account, then the affected server's Plugin connection panel.
- Select Rotate secret.
- Put the new one-time value in
plugins/KarixMCBridge/config.yml. - Fully restart Paper. Do not use
/reload. - Confirm Creator Studio shows a fresh policy sync and review integrity failures, rewards, and purchases from the suspected period.
Never put a plugin secret in screenshots, chat messages, source control, support tickets, or client-side JavaScript. Use a separate random PLUGIN_SECRET_ENCRYPTION_KEY in production and back it up securely; losing it makes stored plugin credentials unreadable.
- HTTPS domain, secure cookies, HSTS, and
allow-insecure-http: falsein every plugin. - PostgreSQL rather than SQLite for concurrent production traffic.
- Reverse-proxy request limits, DDoS protection, firewall rules, monitoring, alerting, encrypted backups, and tested restores.
- Separate least-privilege services and secrets, key rotation, dependency scanning, and a documented incident-response owner.
- Legal review of the privacy policy, consent flow, payments, retention periods, and the rules of every launch region.
- A written bank-reconciliation, duplicate-fulfillment, refund/dispute, mistaken-transfer, and operator-access procedure for the manual beta purchase flow.
Send a private report to the security contact configured for the deployment. Include the affected URL or plugin version, reproduction steps, impact, and relevant logs with secrets and personal data removed. Do not test against other users' accounts or disrupt a live server.