From 00f30c715f625c69289fb2b8d97d923d0edf8689 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 16:42:55 -0600 Subject: [PATCH 01/13] docs: add repository security threat model --- docs/security-threat-model.md | 243 ++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 docs/security-threat-model.md diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md new file mode 100644 index 0000000..7a41f84 --- /dev/null +++ b/docs/security-threat-model.md @@ -0,0 +1,243 @@ +# SimpleAPI security threat model + +This document defines the repository-specific threat model for security review and Codex Security scans. Read it with current source, tests, and AGENTS.md. SimpleAPI is a shared library: it often has no direct attacker-facing entry point, but its primitives sit underneath AdvancedCore and other plugins that do. + +The goal is to identify unsafe shared primitives and trust-boundary violations without treating every generic API or compatibility bug as a vulnerability. + +## Security objectives + +SimpleAPI provides platform-neutral and Bukkit-oriented helpers for SQL, configuration/files, serialization, scheduling, messaging/communication, items/GUI support, reflection/compatibility, and common utilities. + +Important properties are: + +1. Lower-trust values supplied by consuming plugins must not become SQL syntax, filesystem paths, config structure, commands, or unsafe serialized structure unexpectedly. +2. SQL helpers must separate values from identifiers and preserve connection, TLS, and transaction semantics. +3. Generic file/config helpers must not claim containment or safety they do not actually enforce. +4. Server-communication helpers must distinguish confidentiality from authentication and must not silently trust source/origin. +5. Shared serializers and parsers must reject ambiguity when the result is used for authorization, routing, or persistent state. +6. Public APIs must have explicit thread, ownership, and lifecycle semantics so consumers do not accidentally create races or resource leaks. +7. Platform-neutral/shared artifacts must not load platform-specific classes unexpectedly. +8. Attacker-influenced queues, recursion, payloads, retries, caches, and diagnostics must remain bounded where the API promises safe handling. + +## Trust boundaries + +### Lower-trust input + +SimpleAPI callers may pass: + +- player names, UUID-like values, commands, chat/placeholder output, GUI values, vote-service data, proxy/plugin-message data, Redis/socket payloads, and database rows; +- table, column, or data keys derived by a downstream plugin from player or remote values; +- YAML keys/values and filenames selected indirectly by users; +- serialized map/list/string data read from persistent or remote stores; +- remote host, port, or payload values in server-communication wrappers. + +Treat persisted data as tainted if a lower-trust source could have written it earlier. + +### Trusted callers and operators + +A malicious installed plugin already shares the JVM and can usually bypass SimpleAPI entirely. An operator intentionally selecting an arbitrary database, file, network endpoint, or config value is also privileged. + +Security review should focus on benign consumers passing lower-trust data into a helper whose contract suggests safe handling, or on helpers directly used by exposed higher layers. + +## Current controls to preserve + +Current master already includes controls that older findings may predate: + +- SQL value paths commonly use PreparedStatement; +- AbstractSqlTable provides identifier quoting and driver-aware SQL helpers; +- PostgreSQL has explicit TLS modes, including VERIFY_FULL for certificate and hostname verification; +- neutral/shared packaging has explicit platform-isolation expectations; +- concurrency and lifecycle contracts are documented in AGENTS.md. + +Look for bypasses, sibling paths that do not use the same control, and configuration interactions that silently weaken an explicitly selected hardened mode. + +## SQL and database security + +SQL is one of the highest-value shared surfaces. + +### Values, identifiers and raw SQL + +Bind lower-trust values with prepared statements. + +Treat table names, prefixes, column names, type/default expressions, ORDER BY fragments, database names, and DDL as syntax requiring strict construction, quoting, or allowlisting. + +Quoting is not an allowlist for every SQL grammar position. Type/default expressions or raw fragments may need a much narrower parser. + +Search for: + +- one database/driver path concatenating a value while others bind; +- unsafe dynamic identifiers in CREATE, ALTER, UPDATE, or DELETE; +- MySQL, MariaDB, PostgreSQL, or SQLite differences that turn a safe helper into raw syntax on one backend; +- async schema migration racing normal reads/writes; +- failed migration leaving a field/type in a permissive or misleading default state; +- connection errors converting an integrity or authorization read into a success/default; +- connection leaks or retry loops under attacker-triggerable query load; +- transaction helpers committing partial multi-step state. + +Generic raw-query APIs are trusted-power APIs. Do not report their existence alone. + +### PostgreSQL TLS + +SimpleAPI has explicit PostgreSQL TLS modes. VERIFY_FULL is the hardened mode for certificate and hostname verification, while legacy or REQUIRE-style behavior exists for compatibility. + +Do not repeatedly report the existence of encryption-only compatibility behavior as a new vulnerability. Instead test: + +- whether an explicit VERIFY_FULL selection can be downgraded by legacy UseSSL handling; +- whether appended JDBC parameters can override security-sensitive parameters after the library sets them; +- whether parameter ordering changes the final effective security mode; +- whether hostname/certificate verification is actually active in the final JDBC URL; +- whether credentials leak to logs on failed connection; +- whether migration from legacy settings changes security unexpectedly without operator intent. + +A bypass of explicitly selected VERIFY_FULL is security-relevant. Choosing a weaker compatibility mode deliberately is not the same thing. + +## Files, YAML and configuration + +SimpleAPI contains generic file/config primitives used by higher-level plugins. A helper accepting a File from a trusted caller is not automatically responsible for sandboxing the filesystem. + +Security findings require either a helper that promises containment or safe-name behavior and can be bypassed, or a realistic downstream path feeding lower-trust names/paths into it. + +Review: + +- relative and absolute path handling; +- parent traversal, separator variants, Windows drive/UNC paths, and Unicode normalization; +- symlink following and check-then-use races; +- atomic replace and backup semantics; +- YAML keys containing dots or separators altering unintended hierarchy; +- copying/default-merge behavior that unexpectedly overwrites secrets or permissions; +- configuration recursion and cycle handling; +- serialization of platform-native objects into supposedly neutral formats; +- logs/errors exposing full paths or sensitive configuration. + +Do not classify "a trusted plugin can ask a generic file helper to write any file it chooses" as arbitrary-file-write without a lower-trust path or documented containment promise. + +## Serialization and parser ambiguity + +Utility encodings are often reused beyond their original purpose. + +Search map/list/string codecs and delimiter-based formats for: + +- ambiguous delimiters; +- trailing empty fields lost during splitting; +- escaping that is not reversible; +- duplicate keys changing authorization or routing meaning; +- unbounded recursion or nesting; +- parse/serialize mismatch; +- attacker-controlled data turning into additional fields or entries. + +Severity depends on the consumer. A broken round-trip with no security-sensitive caller is a correctness bug. Escalate when the parsed result controls permissions, routing, commands, SQL, or persistent ownership. + +## Server communication and message origin + +SimpleAPI contains reusable communication primitives used by higher-level plugins. + +Do not assume encryption means authentication. Determine the exact guarantee of each helper. + +Search for: + +- unauthenticated messages exposed through an API that consumers reasonably treat as trusted; +- sender/origin identifiers supplied only by the payload without channel binding; +- replay or duplicate delivery; +- confidentiality without integrity/authentication; +- key reuse across protocol domains; +- unbounded payload/message queues; +- reconnect or reload creating duplicate listeners; +- callbacks after close/disable; +- malformed payloads crossing directly into command, config, or deserialization helpers. + +If authentication is intentionally the consuming plugin's responsibility, document that boundary rather than inventing a missing SimpleAPI contract. + +## Concurrency, scheduling and lifecycle + +SimpleAPI is reused on Bukkit/Paper/Folia, proxies, and neutral/native contexts. + +Review public APIs for explicit callback context and ownership. Search for: + +- blocking SQL/network/file work on platform event or region threads; +- Bukkit/world/entity access from arbitrary async workers; +- executor rejection silently dropping accepted work; +- reload/shutdown leaking workers, sockets, timers, or callbacks; +- old-runtime callbacks mutating replacement state; +- unbounded task submission; +- cancellation/interruption swallowed and later reported as success; +- synchronized callbacks invoking external consumer code while internal locks remain held. + +A thread-policy difference is security-relevant only when there is a credible reachable integrity or availability effect. + +## Shared artifact and classloading boundary + +The shared or neutral artifact must remain free of unintended Bukkit, BungeeCord, Velocity, Minecraft, Forge, Fabric, NeoForge, or other loader-specific linkage as documented by the repository. + +This is primarily compatibility and runtime isolation, not attacker security. Escalate only when classloading, reflection, or service descriptors create unintended privileged code execution or expose platform-only capabilities to lower-trust data. + +Otherwise classify accidental platform linkage as compatibility or packaging. + +## Reflection and dynamic loading + +Reflection and class-name utilities are powerful shared primitives. + +Search for lower-trust input reaching: + +- Class.forName or equivalent; +- constructors or method names; +- provider/implementation loading; +- enum/value reflection used to select privileged behavior; +- arbitrary method dispatch based on serialized config. + +A trusted caller choosing a class or reflection target is not RCE by itself. The security boundary is lower-trust control over the target or arguments. + +## Resource exhaustion + +Because SimpleAPI sits under other plugins, persisted/database data can be attacker-influenced even if a helper has no socket. + +Prioritize: + +- unbounded SQL result materialization; +- connection-pool starvation; +- queue/cache cardinality controlled by arbitrary keys; +- recursive config/object conversion; +- huge strings or serialized collections; +- reconnect/retry loops; +- per-item or per-row task creation; +- log amplification. + +Require a realistic caller path and concrete resource effect. + +## Secrets, logging and errors + +Database passwords, tokens, private keys, Authorization-like values, and JDBC URLs containing credentials must not appear in routine logs or exceptions returned to lower-trust callers. + +Connection diagnostics may include host/database identifiers where operationally useful, but avoid full credential-bearing URLs and raw sensitive configuration. + +## Supply chain and compatibility + +CI findings matter when untrusted PR-controlled code receives write-capable repository credentials, can poison trusted caches or artifacts, or can modify releases. + +SimpleAPI strongly values drop-in and API compatibility. Do not classify public signature changes, classifier/package regressions, config defaults, or platform leakage as security unless they cross a real trust boundary. + +## High-value attack stories + +1. Pass attacker-controlled strings through every SQL value API and dynamic identifier API across SQLite, MySQL/MariaDB, and PostgreSQL. +2. Configure PostgreSQL VERIFY_FULL, then try parameter ordering and legacy-setting combinations that downgrade the final JDBC URL. +3. Feed traversal, separator, symlink, and normalization variants through helpers that claim safe child-path or contained-file behavior. +4. Round-trip strings containing every delimiter, escape, and trailing-empty case through shared serializers, then use the result in a security-sensitive consumer. +5. Reload or close a communication helper while messages and reconnects are in flight and verify single-listener ownership. +6. Saturate SQL pools or async queues through a bounded lower-trust caller and verify failure is bounded and fail-safe. +7. Trigger config/object conversion on cyclic, deeply nested, or very large data. +8. Pass lower-trust class, method, or provider names through reflection and dynamic-loading helpers. +9. Shut down while file, SQL, or network tasks are accepted and verify no stale callback mutates replacement state. +10. Package the neutral/shared artifact and inspect signatures, annotations, static initializers, and service descriptors for unexpected platform linkage. + +## Scan calibration and severity + +Critical: ordinary-player or remote input reaches arbitrary JVM code execution, arbitrary host/plugin file write, or SQL syntax capable of modifying unrelated data through a SimpleAPI helper contract. + +High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS verification bypass despite explicit VERIFY_FULL; repeatable cross-user/state corruption or resource exhaustion affecting the server. + +Medium: parser/serialization ambiguity with a security-sensitive consumer; bounded but practical database or queue DoS; meaningful credential disclosure to limited readers; lifecycle races causing occasional duplicate or lost privileged operations. + +Low: defense-in-depth hardening, minor log/path disclosure, compatibility-only TLS legacy behavior, or generic API misuse requiring a fully malicious installed plugin. + +Usually not security by itself: API/ABI/classifier regressions, malformed trusted config, a trusted caller choosing arbitrary files, SQL, or endpoints, delimiter bugs with no security-sensitive consumer, or accidental platform linkage without a trust-boundary effect. + +For every finding identify the consuming path, lower-trust source, helper contract, final security-sensitive sink, and whether current master still exposes the issue. From 6fb7d0a186e46a441d3a8c927dfba12a4dca973f Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 16:42:58 -0600 Subject: [PATCH 02/13] docs: point agents to security threat model --- AGENTS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index fa96783..3e2c53e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,6 +2,10 @@ SimpleAPI is a shared library consumed by AdvancedCore and other plugins. The repository now uses one Maven project and one source tree with platform-neutral and platform-specific packages; do not recreate the removed experimental submodule build. +## Security threat model + +For security reviews, vulnerability triage, and security-sensitive changes, read docs/security-threat-model.md before classifying or fixing findings. Treat it as the repository-specific attacker/trust-boundary model; verify every conclusion against current code and tests. Do not promote compatibility, trusted-operator behavior, or generic correctness bugs into security findings unless the documented boundary is actually crossed. + ## Build and verification Requirements: JDK 21+ and Maven. The Maven project is in `SimpleAPI/`. From 5f0eff35a358f12e12aae05124c927a1b60f6131 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 16:55:00 -0600 Subject: [PATCH 03/13] docs: add at-rest credential trust boundary --- docs/security-threat-model.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index 7a41f84..5b4ddb9 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -39,6 +39,12 @@ A malicious installed plugin already shares the JVM and can usually bypass Simpl Security review should focus on benign consumers passing lower-trust data into a helper whose contract suggests safe handling, or on helpers directly used by exposed higher layers. +### Local OS principals and persisted private state + +Other local OS accounts/processes that do **not** already run as the Minecraft server account are a distinct lower-trust boundary for persisted HTTP credentials and private material. Same-UID malicious plugin code is outside meaningful filesystem isolation, but unrelated local principals should not be able to read CA/server/client private keys, credential passwords, enrollment state, or active/staged credential generations. + +Review owner-only permissions, no-follow/symlink checks, atomic publication, durability, staged-generation cleanup, rotation/revocation, and failure behavior. A regression that broadens private-file or private-directory permissions, publishes sensitive data before permissions are enforced, leaves superseded private generations readable indefinitely, or silently continues when owner-only permissions cannot be proven crosses this boundary. + ## Current controls to preserve Current master already includes controls that older findings may predate: @@ -46,6 +52,7 @@ Current master already includes controls that older findings may predate: - SQL value paths commonly use PreparedStatement; - AbstractSqlTable provides identifier quoting and driver-aware SQL helpers; - PostgreSQL has explicit TLS modes, including VERIFY_FULL for certificate and hostname verification; +- HTTP TLS identity, client credential, enrollment-state, and durable-delivery paths use `PrivateFilePermissions` plus no-follow/owner-only checks where private state is persisted; - neutral/shared packaging has explicit platform-isolation expectations; - concurrency and lifecycle contracts are documented in AGENTS.md. @@ -203,10 +210,12 @@ Prioritize: Require a realistic caller path and concrete resource effect. -## Secrets, logging and errors +## Secrets, private files, logging and errors Database passwords, tokens, private keys, Authorization-like values, and JDBC URLs containing credentials must not appear in routine logs or exceptions returned to lower-trust callers. +For HTTP transport state, review `HttpTlsIdentity`, `HttpClientCredentialStore`, `HttpEnrollmentAuthority`, durable delivery state, and `PrivateFilePermissions` together. Private files/directories should remain owner-only; symlinks and unsafe file types must be rejected where promised; temporary/staged generations must receive safe permissions before sensitive bytes are written; activation/rotation must not briefly expose weaker permissions; cleanup must not accidentally delete or retain the wrong active generation; and restart/recovery must re-validate permissions rather than trusting prior creation. + Connection diagnostics may include host/database identifiers where operationally useful, but avoid full credential-bearing URLs and raw sensitive configuration. ## Supply chain and compatibility From e98e4d4b047ced95e5d23e3d91bbb062de607f4b Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 17:02:19 -0600 Subject: [PATCH 04/13] docs: expand SimpleAPI secret and bootstrap boundaries --- docs/security-threat-model.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index 5b4ddb9..23d6525 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -39,12 +39,20 @@ A malicious installed plugin already shares the JVM and can usually bypass Simpl Security review should focus on benign consumers passing lower-trust data into a helper whose contract suggests safe handling, or on helpers directly used by exposed higher layers. +### HTTP enrollment bootstrap + +The copy/paste HTTP connection code is bootstrap trust material. Its embedded MAC is keyed by the token contained in the same code, so it detects corruption but does **not** authenticate wholesale replacement of the code. Initial endpoint and certificate trust therefore depends on the operator receiving the complete connection code through an authentic and confidential administrative channel. + +Treat interception, replacement, relay, disclosure, replay-before-consumption, and expiry handling of the connection code as part of this out-of-band bootstrap boundary. Do not blame the HTTP transport for an attacker who already controls that trusted delivery channel, but do report cases where the implementation accepts an expired/replayed/wrong-server code, fails to bind the resulting certificate to the advertised identity, or leaks the code/token outside that channel. + ### Local OS principals and persisted private state -Other local OS accounts/processes that do **not** already run as the Minecraft server account are a distinct lower-trust boundary for persisted HTTP credentials and private material. Same-UID malicious plugin code is outside meaningful filesystem isolation, but unrelated local principals should not be able to read CA/server/client private keys, credential passwords, enrollment state, or active/staged credential generations. +Other local OS accounts/processes that do **not** already run as the Minecraft server account are a distinct lower-trust boundary for **all persisted cryptographic secrets and credentials**, not only the HTTP transport. Same-UID malicious plugin code is outside meaningful filesystem isolation, but unrelated local principals should not be able to read CA/server/client private keys, credential passwords, enrollment state, active/staged credential generations, socket/shared-transport AES keys, or other reusable secrets that protect message confidentiality or authentication. Review owner-only permissions, no-follow/symlink checks, atomic publication, durability, staged-generation cleanup, rotation/revocation, and failure behavior. A regression that broadens private-file or private-directory permissions, publishes sensitive data before permissions are enforced, leaves superseded private generations readable indefinitely, or silently continues when owner-only permissions cannot be proven crosses this boundary. +Current HTTP credential paths use `PrivateFilePermissions` and related no-follow checks. The legacy `com.bencodez.simpleapi.encryption.EncryptionHandler.save` path is a separate review target: it writes its AES key with ordinary `FileWriter` semantics and does not currently establish the same owner-only guarantee. Do not let the stronger HTTP storage controls imply that this or other non-HTTP secret stores are equally protected. + ## Current controls to preserve Current master already includes controls that older findings may predate: @@ -52,7 +60,7 @@ Current master already includes controls that older findings may predate: - SQL value paths commonly use PreparedStatement; - AbstractSqlTable provides identifier quoting and driver-aware SQL helpers; - PostgreSQL has explicit TLS modes, including VERIFY_FULL for certificate and hostname verification; -- HTTP TLS identity, client credential, enrollment-state, and durable-delivery paths use `PrivateFilePermissions` plus no-follow/owner-only checks where private state is persisted; +- HTTP TLS identity, client credential, enrollment-state, and durable-delivery paths use `PrivateFilePermissions` plus no-follow/owner-only checks where private state is persisted; this control is path-specific and does not cover every persisted secret (for example the legacy `EncryptionHandler` AES key path); - neutral/shared packaging has explicit platform-isolation expectations; - concurrency and lifecycle contracts are documented in AGENTS.md. @@ -212,10 +220,12 @@ Require a realistic caller path and concrete resource effect. ## Secrets, private files, logging and errors -Database passwords, tokens, private keys, Authorization-like values, and JDBC URLs containing credentials must not appear in routine logs or exceptions returned to lower-trust callers. +Database passwords, tokens, private keys, reusable encryption keys, Authorization-like values, enrollment codes, and JDBC URLs containing credentials must not appear in routine logs or exceptions returned to lower-trust callers. For HTTP transport state, review `HttpTlsIdentity`, `HttpClientCredentialStore`, `HttpEnrollmentAuthority`, durable delivery state, and `PrivateFilePermissions` together. Private files/directories should remain owner-only; symlinks and unsafe file types must be rejected where promised; temporary/staged generations must receive safe permissions before sensitive bytes are written; activation/rotation must not briefly expose weaker permissions; cleanup must not accidentally delete or retain the wrong active generation; and restart/recovery must re-validate permissions rather than trusting prior creation. +Apply the same local-principal reasoning to non-HTTP cryptographic material. In particular, the AES key persisted by `EncryptionHandler` is reusable secret material even though that legacy helper does not provide the HTTP stack's owner-only persistence guarantees. Review creation-time permissions, existing-file revalidation, symlink/file-type handling, key rotation, cleanup, and whether disclosure would let another local principal decrypt or forge protected traffic. + Connection diagnostics may include host/database identifiers where operationally useful, but avoid full credential-bearing URLs and raw sensitive configuration. ## Supply chain and compatibility @@ -236,12 +246,14 @@ SimpleAPI strongly values drop-in and API compatibility. Do not classify public 8. Pass lower-trust class, method, or provider names through reflection and dynamic-loading helpers. 9. Shut down while file, SQL, or network tasks are accepted and verify no stale callback mutates replacement state. 10. Package the neutral/shared artifact and inspect signatures, annotations, static initializers, and service descriptors for unexpected platform linkage. +11. Replace, relay, replay, or disclose an HTTP connection code before enrollment and verify the implementation relies only on the explicitly trusted out-of-band delivery channel, code expiry, single-use semantics, identity binding, and pinned certificate data. +12. Create/load every persisted cryptographic secret under permissive umask and mixed local-account conditions; verify paths that promise private storage actually enforce it, and identify legacy paths such as `EncryptionHandler` that do not. ## Scan calibration and severity Critical: ordinary-player or remote input reaches arbitrary JVM code execution, arbitrary host/plugin file write, or SQL syntax capable of modifying unrelated data through a SimpleAPI helper contract. -High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS verification bypass despite explicit VERIFY_FULL; repeatable cross-user/state corruption or resource exhaustion affecting the server. +High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS verification bypass despite explicit VERIFY_FULL; exposure of reusable cryptographic keys or HTTP client/server credentials to an unrelated local principal where private storage is expected; repeatable cross-user/state corruption or resource exhaustion affecting the server. Medium: parser/serialization ambiguity with a security-sensitive consumer; bounded but practical database or queue DoS; meaningful credential disclosure to limited readers; lifecycle races causing occasional duplicate or lost privileged operations. From c5ef9842296ed2f7e8af23d8b1d53db5fe121836 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 17:10:45 -0600 Subject: [PATCH 05/13] docs: add dependency provenance to threat model --- docs/security-threat-model.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index 23d6525..0c23e08 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -228,10 +228,16 @@ Apply the same local-principal reasoning to non-HTTP cryptographic material. In Connection diagnostics may include host/database identifiers where operationally useful, but avoid full credential-bearing URLs and raw sensitive configuration. -## Supply chain and compatibility +## Supply chain, dependency provenance and compatibility + +Supply-chain review covers both CI privileges and the provenance of build inputs that become part of published artifacts. CI findings matter when untrusted PR-controlled code receives write-capable repository credentials, can poison trusted caches or artifacts, or can modify releases. +Also review Maven repository and dependency trust because SimpleAPI resolves artifacts from multiple configured repositories and shades compile-scope dependencies into distributed JARs. Relevant targets include repository compromise, dependency substitution/confusion, mutable or replaced `SNAPSHOT` artifacts, vulnerable or malicious transitives, mismatched checksums/signatures where provenance controls exist, and release builds resolving bytes different from those previously reviewed or tested. + +Do not automatically classify every external repository or intentional development `SNAPSHOT` as a vulnerability. Severity should depend on whether a lower-trust or compromised upstream can alter the bytes used in a trusted build/release, whether those bytes are shaded or executed at runtime, and whether reproducibility/provenance controls would detect the substitution. + SimpleAPI strongly values drop-in and API compatibility. Do not classify public signature changes, classifier/package regressions, config defaults, or platform leakage as security unless they cross a real trust boundary. ## High-value attack stories @@ -248,6 +254,7 @@ SimpleAPI strongly values drop-in and API compatibility. Do not classify public 10. Package the neutral/shared artifact and inspect signatures, annotations, static initializers, and service descriptors for unexpected platform linkage. 11. Replace, relay, replay, or disclose an HTTP connection code before enrollment and verify the implementation relies only on the explicitly trusted out-of-band delivery channel, code expiry, single-use semantics, identity binding, and pinned certificate data. 12. Create/load every persisted cryptographic secret under permissive umask and mixed local-account conditions; verify paths that promise private storage actually enforce it, and identify legacy paths such as `EncryptionHandler` that do not. +13. Rebuild from the same source while varying Maven repository availability, mutable snapshot contents, and transitive resolution; verify reviewed/released artifacts cannot silently substitute different shaded runtime bytes without detection. ## Scan calibration and severity @@ -257,7 +264,7 @@ High: realistic lower-trust SQL injection; authentication/origin bypass in a tra Medium: parser/serialization ambiguity with a security-sensitive consumer; bounded but practical database or queue DoS; meaningful credential disclosure to limited readers; lifecycle races causing occasional duplicate or lost privileged operations. -Low: defense-in-depth hardening, minor log/path disclosure, compatibility-only TLS legacy behavior, or generic API misuse requiring a fully malicious installed plugin. +Low: defense-in-depth hardening, minor log/path disclosure, compatibility-only TLS legacy behavior, generic dependency-hygiene concerns without a concrete artifact-substitution path, or generic API misuse requiring a fully malicious installed plugin. Usually not security by itself: API/ABI/classifier regressions, malformed trusted config, a trusted caller choosing arbitrary files, SQL, or endpoints, delimiter bugs with no security-sensitive consumer, or accidental platform linkage without a trust-boundary effect. From d142a62db7e0fbc66694bd4b1e23d588389b0788 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 17:28:21 -0600 Subject: [PATCH 06/13] docs: define remote-peer and network-observer boundary --- docs/security-threat-model.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index 0c23e08..af36c6e 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -39,6 +39,20 @@ A malicious installed plugin already shares the JVM and can usually bypass Simpl Security review should focus on benign consumers passing lower-trust data into a helper whose contract suggests safe handling, or on helpers directly used by exposed higher layers. +### Remote peers and on-path network observers + +Choosing a host, broker, database, or socket endpoint is an operator decision, but that does **not** make the selected remote peer, DNS/network path, or other hosts/tenants able to observe or modify traffic trusted. Treat an on-path observer and a compromised/malicious remote service as lower-trust actors unless the selected transport provides and successfully verifies the required confidentiality and peer/message authentication. + +Review the guarantee transport by transport: + +- HTTP transport is the strong authenticated case: private-CA TLS, certificate/hostname/pin checks, enrolled peer identity, bounded protocol messages, and replay/delivery state should protect against passive and active network observers when those checks succeed. +- Redis supports optional TLS. The constructor defaults to `ssl=false`; username/password authentication over plaintext does not protect credentials or payloads from an on-path observer. When TLS is enabled, hostname identification must remain active. +- MQTT accepts caller-supplied broker URLs/options and the convenience username/password constructor does not itself require TLS. The security of credentials and payloads therefore depends on the selected MQTT scheme/options and broker configuration. +- Raw socket transport has no intrinsic peer identity. Legacy `EncryptionHandler` AES provides optional confidentiality but does not by itself provide authenticated encryption, sender identity, or replay protection. +- MySQL/MariaDB `UseSSL` may provide encryption, but the repository does not treat that flag alone as a promise of hostname/certificate identity verification. PostgreSQL `VERIFY_FULL` is the explicit verified-TLS mode for that driver. + +Do not classify intentional plaintext/private-network compatibility as an authentication bypass by itself. Do report silent downgrade from an explicitly selected secure mode, credential disclosure where the API/configuration claims protection, peer-identity verification bypass, or code that treats an unauthenticated/plaintext channel as stronger than its documented guarantee. + ### HTTP enrollment bootstrap The copy/paste HTTP connection code is bootstrap trust material. Its embedded MAC is keyed by the token contained in the same code, so it detects corruption but does **not** authenticate wholesale replacement of the code. Initial endpoint and certificate trust therefore depends on the operator receiving the complete connection code through an authentic and confidential administrative channel. @@ -146,13 +160,14 @@ Severity depends on the consumer. A broken round-trip with no security-sensitive SimpleAPI contains reusable communication primitives used by higher-level plugins. -Do not assume encryption means authentication. Determine the exact guarantee of each helper. +Do not assume an operator-selected endpoint is trustworthy merely because it is configured, and do not assume encryption means authentication. Include both malicious remote peers and on-path network observers in the analysis, then determine the exact confidentiality, peer-identity, message-integrity, and replay guarantee of each helper. Search for: - unauthenticated messages exposed through an API that consumers reasonably treat as trusted; - sender/origin identifiers supplied only by the payload without channel binding; - replay or duplicate delivery; +- plaintext credential or payload exposure to on-path observers where a secure mode was expected; - confidentiality without integrity/authentication; - key reuse across protocol domains; - unbounded payload/message queues; @@ -255,12 +270,13 @@ SimpleAPI strongly values drop-in and API compatibility. Do not classify public 11. Replace, relay, replay, or disclose an HTTP connection code before enrollment and verify the implementation relies only on the explicitly trusted out-of-band delivery channel, code expiry, single-use semantics, identity binding, and pinned certificate data. 12. Create/load every persisted cryptographic secret under permissive umask and mixed local-account conditions; verify paths that promise private storage actually enforce it, and identify legacy paths such as `EncryptionHandler` that do not. 13. Rebuild from the same source while varying Maven repository availability, mutable snapshot contents, and transitive resolution; verify reviewed/released artifacts cannot silently substitute different shaded runtime bytes without detection. +14. Place an active network observer or malicious endpoint between each non-HTTP transport and its configured peer; verify plaintext/optional-TLS modes are classified according to their real guarantees, secure modes cannot silently downgrade, credentials are protected when promised, and unauthenticated encryption is never mistaken for peer identity or message authenticity. ## Scan calibration and severity Critical: ordinary-player or remote input reaches arbitrary JVM code execution, arbitrary host/plugin file write, or SQL syntax capable of modifying unrelated data through a SimpleAPI helper contract. -High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS verification bypass despite explicit VERIFY_FULL; exposure of reusable cryptographic keys or HTTP client/server credentials to an unrelated local principal where private storage is expected; repeatable cross-user/state corruption or resource exhaustion affecting the server. +High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS/peer-identity verification bypass despite an explicitly selected verified mode; exposure of reusable network credentials or cryptographic keys to an on-path observer when the configured mode promises their protection; exposure of reusable cryptographic keys or HTTP client/server credentials to an unrelated local principal where private storage is expected; repeatable cross-user/state corruption or resource exhaustion affecting the server. Medium: parser/serialization ambiguity with a security-sensitive consumer; bounded but practical database or queue DoS; meaningful credential disclosure to limited readers; lifecycle races causing occasional duplicate or lost privileged operations. From 4e7de846e3ceecf6e5e1ea42f47321e687c34044 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 17:35:31 -0600 Subject: [PATCH 07/13] docs: keep authenticated remote peers lower trust --- docs/security-threat-model.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index af36c6e..96eee54 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -41,17 +41,17 @@ Security review should focus on benign consumers passing lower-trust data into a ### Remote peers and on-path network observers -Choosing a host, broker, database, or socket endpoint is an operator decision, but that does **not** make the selected remote peer, DNS/network path, or other hosts/tenants able to observe or modify traffic trusted. Treat an on-path observer and a compromised/malicious remote service as lower-trust actors unless the selected transport provides and successfully verifies the required confidentiality and peer/message authentication. +Choosing a host, broker, database, or socket endpoint is an operator decision, but that does **not** make the selected remote peer, DNS/network path, or other hosts/tenants able to observe or modify traffic trusted. Treat both on-path observers and compromised/malicious remote services as lower-trust actors. Successful TLS, certificate, broker, database, or message authentication can establish peer identity and neutralize some on-path impersonation/tampering risks, but it does **not** make the authenticated peer's payload, database rows, broker messages, or envelope fields trusted input. Review the guarantee transport by transport: -- HTTP transport is the strong authenticated case: private-CA TLS, certificate/hostname/pin checks, enrolled peer identity, bounded protocol messages, and replay/delivery state should protect against passive and active network observers when those checks succeed. +- HTTP transport is the strong authenticated case against on-path impersonation: private-CA TLS, certificate/hostname/pin checks, enrolled peer identity, bounded protocol messages, and replay/delivery state should protect against passive and active network observers when those checks succeed. An authenticated backend/proxy remains lower-trust for message contents and operation authorization; identity proof does not authorize every subchannel or payload. - Redis supports optional TLS. The constructor defaults to `ssl=false`; username/password authentication over plaintext does not protect credentials or payloads from an on-path observer. When TLS is enabled, hostname identification must remain active. - MQTT accepts caller-supplied broker URLs/options and the convenience username/password constructor does not itself require TLS. The security of credentials and payloads therefore depends on the selected MQTT scheme/options and broker configuration. - Raw socket transport has no intrinsic peer identity. Legacy `EncryptionHandler` AES provides optional confidentiality but does not by itself provide authenticated encryption, sender identity, or replay protection. - MySQL/MariaDB `UseSSL` may provide encryption, but the repository does not treat that flag alone as a promise of hostname/certificate identity verification. PostgreSQL `VERIFY_FULL` is the explicit verified-TLS mode for that driver. -Do not classify intentional plaintext/private-network compatibility as an authentication bypass by itself. Do report silent downgrade from an explicitly selected secure mode, credential disclosure where the API/configuration claims protection, peer-identity verification bypass, or code that treats an unauthenticated/plaintext channel as stronger than its documented guarantee. +Do not classify intentional plaintext/private-network compatibility as an authentication bypass by itself. Do report silent downgrade from an explicitly selected secure mode, credential disclosure where the API/configuration claims protection, peer-identity verification bypass, or code that treats an unauthenticated/plaintext channel as stronger than its documented guarantee. Separately, continue treating authenticated peers as lower-trust data sources: a compromised backend, database, Redis server, or MQTT broker may send hostile but correctly authenticated content, which must still be schema-validated, authorized, and bounded before privileged callbacks or persistence. ### HTTP enrollment bootstrap @@ -160,7 +160,7 @@ Severity depends on the consumer. A broken round-trip with no security-sensitive SimpleAPI contains reusable communication primitives used by higher-level plugins. -Do not assume an operator-selected endpoint is trustworthy merely because it is configured, and do not assume encryption means authentication. Include both malicious remote peers and on-path network observers in the analysis, then determine the exact confidentiality, peer-identity, message-integrity, and replay guarantee of each helper. +Do not assume an operator-selected endpoint is trustworthy merely because it is configured, and do not assume encryption means authentication. Include both malicious/compromised remote peers and on-path network observers in the analysis. First determine the exact confidentiality, peer-identity, message-integrity, and replay guarantee of each helper; then continue validating and authorizing the authenticated peer's content as lower-trust input. Search for: From 8790f24dba5c6ce89e5a44017d711086c9555475 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 17:40:45 -0600 Subject: [PATCH 08/13] docs: add local configuration integrity boundary --- docs/security-threat-model.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index 96eee54..668c5f5 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -59,13 +59,15 @@ The copy/paste HTTP connection code is bootstrap trust material. Its embedded MA Treat interception, replacement, relay, disclosure, replay-before-consumption, and expiry handling of the connection code as part of this out-of-band bootstrap boundary. Do not blame the HTTP transport for an attacker who already controls that trusted delivery channel, but do report cases where the implementation accepts an expired/replayed/wrong-server code, fails to bind the resulting certificate to the advertised identity, or leaks the code/token outside that channel. -### Local OS principals and persisted private state +### Local OS principals and security-critical persisted state -Other local OS accounts/processes that do **not** already run as the Minecraft server account are a distinct lower-trust boundary for **all persisted cryptographic secrets and credentials**, not only the HTTP transport. Same-UID malicious plugin code is outside meaningful filesystem isolation, but unrelated local principals should not be able to read CA/server/client private keys, credential passwords, enrollment state, active/staged credential generations, socket/shared-transport AES keys, or other reusable secrets that protect message confidentiality or authentication. +Other local OS accounts/processes that do **not** already run as the Minecraft server account are a distinct lower-trust boundary for security-critical persisted state, including both secrets and configuration that controls trust decisions. Same-UID malicious plugin code is outside meaningful filesystem isolation, but unrelated local principals should not be able to read reusable credentials/keys **or modify** operator-owned configuration and state in ways that redirect connections, weaken TLS/authentication, change trusted endpoints, alter identity bindings, or change executable/runtime behavior. -Review owner-only permissions, no-follow/symlink checks, atomic publication, durability, staged-generation cleanup, rotation/revocation, and failure behavior. A regression that broadens private-file or private-directory permissions, publishes sensitive data before permissions are enforced, leaves superseded private generations readable indefinitely, or silently continues when owner-only permissions cannot be proven crosses this boundary. +This includes CA/server/client private keys, credential passwords, enrollment state, active/staged credential generations, socket/shared-transport AES keys, database/broker credentials, and security-sensitive YAML/properties such as database host, driver/type, TLS mode, `UseSSL`, broker/socket endpoints, connection-code state, trusted pins/identities, and other persisted values that determine who or what the process trusts. -Current HTTP credential paths use `PrivateFilePermissions` and related no-follow checks. The legacy `com.bencodez.simpleapi.encryption.EncryptionHandler.save` path is a separate review target: it writes its AES key with ordinary `FileWriter` semantics and does not currently establish the same owner-only guarantee. Do not let the stronger HTTP storage controls imply that this or other non-HTTP secret stores are equally protected. +Review file and directory ownership/permissions, no-follow/symlink checks, atomic publication, durability, unauthorized replacement, staged-generation cleanup, rotation/revocation, and failure behavior. A regression that broadens access, permits an unrelated local principal to replace security-critical configuration/state, publishes sensitive data before permissions are enforced, leaves superseded private generations readable indefinitely, or silently continues when a promised ownership/permission invariant cannot be proven crosses this boundary. + +Current HTTP credential paths use `PrivateFilePermissions` and related no-follow checks. The legacy `com.bencodez.simpleapi.encryption.EncryptionHandler.save` path is a separate review target: it writes its AES key with ordinary `FileWriter` semantics and does not currently establish the same owner-only guarantee. Likewise, generic YAML/config loaders such as MySQL configuration parsing consume security-sensitive endpoint/TLS/credential settings supplied by the embedding plugin; the operator's intended values are trusted, but unauthorized local modification of those persisted values is not. Do not let stronger HTTP storage controls imply that non-HTTP secret stores or ordinary config files have equivalent integrity protection. ## Current controls to preserve @@ -122,7 +124,7 @@ A bypass of explicitly selected VERIFY_FULL is security-relevant. Choosing a wea ## Files, YAML and configuration -SimpleAPI contains generic file/config primitives used by higher-level plugins. A helper accepting a File from a trusted caller is not automatically responsible for sandboxing the filesystem. +SimpleAPI contains generic file/config primitives used by higher-level plugins. A helper accepting a File from a trusted caller is not automatically responsible for sandboxing the filesystem. However, the **integrity** of operator-owned security configuration is part of the local-principal boundary: another OS account rewriting a trusted config file is not equivalent to the operator intentionally selecting those values. Security findings require either a helper that promises containment or safe-name behavior and can be bypassed, or a realistic downstream path feeding lower-trust names/paths into it. @@ -136,7 +138,8 @@ Review: - copying/default-merge behavior that unexpectedly overwrites secrets or permissions; - configuration recursion and cycle handling; - serialization of platform-native objects into supposedly neutral formats; -- logs/errors exposing full paths or sensitive configuration. +- logs/errors exposing full paths or sensitive configuration; +- unauthorized local replacement of security-sensitive config or state that changes endpoints, TLS/authentication modes, credentials, identity bindings, or other trust decisions. Do not classify "a trusted plugin can ask a generic file helper to write any file it chooses" as arbitrary-file-write without a lower-trust path or documented containment promise. @@ -276,7 +279,7 @@ SimpleAPI strongly values drop-in and API compatibility. Do not classify public Critical: ordinary-player or remote input reaches arbitrary JVM code execution, arbitrary host/plugin file write, or SQL syntax capable of modifying unrelated data through a SimpleAPI helper contract. -High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS/peer-identity verification bypass despite an explicitly selected verified mode; exposure of reusable network credentials or cryptographic keys to an on-path observer when the configured mode promises their protection; exposure of reusable cryptographic keys or HTTP client/server credentials to an unrelated local principal where private storage is expected; repeatable cross-user/state corruption or resource exhaustion affecting the server. +High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS/peer-identity verification bypass despite an explicitly selected verified mode; exposure of reusable network credentials or cryptographic keys to an on-path observer when the configured mode promises their protection; exposure of reusable cryptographic keys or HTTP client/server credentials to an unrelated local principal where private storage is expected; unauthorized local modification of security-critical configuration/state that redirects or weakens a protected connection or identity boundary; repeatable cross-user/state corruption or resource exhaustion affecting the server. Medium: parser/serialization ambiguity with a security-sensitive consumer; bounded but practical database or queue DoS; meaningful credential disclosure to limited readers; lifecycle races causing occasional duplicate or lost privileged operations. From 220d225eedaa27d28f9981758b34e9926ceacc43 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 17:47:55 -0600 Subject: [PATCH 09/13] docs: add telemetry egress trust boundary --- docs/security-threat-model.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index 668c5f5..66e4d6b 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -236,6 +236,21 @@ Prioritize: Require a realistic caller path and concrete resource effect. +## Outbound telemetry and third-party egress + +Metrics/telemetry is an outbound trust boundary even when the destination is intentionally configured or built in. When bStats or another telemetry path is enabled, data leaves the operator-controlled server and is disclosed to a third party. + +Review telemetry code such as `BStatsMetrics.submitData` / `sendData` and custom-chart registration for: + +- preserving the documented/operator opt-out and never submitting after metrics are disabled; +- avoiding player names, UUIDs, chat, IPs, credentials, database/broker endpoints, configuration secrets, raw logs, or other sensitive plugin/server state unless that specific field is explicitly part of the telemetry contract; +- minimizing persistent identifiers and ensuring a server UUID or similar installation identifier is not reused for unrelated tracking purposes; +- preventing lower-trust custom-chart values or consumer-provided labels from smuggling secrets or unbounded/high-cardinality data into outbound requests; +- bounding request size, retry behavior, failure logging, and network work so telemetry cannot affect server availability; +- keeping telemetry failure isolated from normal plugin/runtime behavior. + +The existence of opt-in/default metrics is not by itself a vulnerability. Security-relevant regressions include ignoring the opt-out, expanding data collection beyond the documented contract, leaking sensitive values, or allowing lower-trust input to influence telemetry egress unexpectedly. + ## Secrets, private files, logging and errors Database passwords, tokens, private keys, reusable encryption keys, Authorization-like values, enrollment codes, and JDBC URLs containing credentials must not appear in routine logs or exceptions returned to lower-trust callers. @@ -274,6 +289,7 @@ SimpleAPI strongly values drop-in and API compatibility. Do not classify public 12. Create/load every persisted cryptographic secret under permissive umask and mixed local-account conditions; verify paths that promise private storage actually enforce it, and identify legacy paths such as `EncryptionHandler` that do not. 13. Rebuild from the same source while varying Maven repository availability, mutable snapshot contents, and transitive resolution; verify reviewed/released artifacts cannot silently substitute different shaded runtime bytes without detection. 14. Place an active network observer or malicious endpoint between each non-HTTP transport and its configured peer; verify plaintext/optional-TLS modes are classified according to their real guarantees, secure modes cannot silently downgrade, credentials are protected when promised, and unauthenticated encryption is never mistaken for peer identity or message authenticity. +15. Enable and disable bStats/telemetry repeatedly, inspect every outbound field and custom chart, and verify opt-out is respected, only documented/minimized metadata leaves the server, lower-trust data cannot inject secrets or unbounded values, and telemetry failures remain isolated. ## Scan calibration and severity @@ -281,7 +297,7 @@ Critical: ordinary-player or remote input reaches arbitrary JVM code execution, High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS/peer-identity verification bypass despite an explicitly selected verified mode; exposure of reusable network credentials or cryptographic keys to an on-path observer when the configured mode promises their protection; exposure of reusable cryptographic keys or HTTP client/server credentials to an unrelated local principal where private storage is expected; unauthorized local modification of security-critical configuration/state that redirects or weakens a protected connection or identity boundary; repeatable cross-user/state corruption or resource exhaustion affecting the server. -Medium: parser/serialization ambiguity with a security-sensitive consumer; bounded but practical database or queue DoS; meaningful credential disclosure to limited readers; lifecycle races causing occasional duplicate or lost privileged operations. +Medium: parser/serialization ambiguity with a security-sensitive consumer; bounded but practical database or queue DoS; meaningful credential disclosure to limited readers; unintended telemetry disclosure of sensitive server/plugin/player data to a third party; lifecycle races causing occasional duplicate or lost privileged operations. Low: defense-in-depth hardening, minor log/path disclosure, compatibility-only TLS legacy behavior, generic dependency-hygiene concerns without a concrete artifact-substitution path, or generic API misuse requiring a fully malicious installed plugin. From e80dddd5e3ea4f8407379894926adf7eb5b4b6df Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 17:53:07 -0600 Subject: [PATCH 10/13] docs: add command authorization and qualify legacy AES --- docs/security-threat-model.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index 66e4d6b..d744225 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -48,7 +48,7 @@ Review the guarantee transport by transport: - HTTP transport is the strong authenticated case against on-path impersonation: private-CA TLS, certificate/hostname/pin checks, enrolled peer identity, bounded protocol messages, and replay/delivery state should protect against passive and active network observers when those checks succeed. An authenticated backend/proxy remains lower-trust for message contents and operation authorization; identity proof does not authorize every subchannel or payload. - Redis supports optional TLS. The constructor defaults to `ssl=false`; username/password authentication over plaintext does not protect credentials or payloads from an on-path observer. When TLS is enabled, hostname identification must remain active. - MQTT accepts caller-supplied broker URLs/options and the convenience username/password constructor does not itself require TLS. The security of credentials and payloads therefore depends on the selected MQTT scheme/options and broker configuration. -- Raw socket transport has no intrinsic peer identity. Legacy `EncryptionHandler` AES provides optional confidentiality but does not by itself provide authenticated encryption, sender identity, or replay protection. +- Raw socket transport has no intrinsic peer identity. Legacy `EncryptionHandler` calls `Cipher.getInstance("AES")` without an explicit mode, IV, or nonce; on common providers this resolves to deterministic ECB-style encryption. Treat it only as legacy obfuscation/limited confidentiality, **not** as modern semantic confidentiality, authenticated encryption, sender identity, or replay protection. Review the actual provider mode, IV/nonce use, key reuse, padding, integrity/MAC coverage, and whether repeated plaintext patterns remain visible. - MySQL/MariaDB `UseSSL` may provide encryption, but the repository does not treat that flag alone as a promise of hostname/certificate identity verification. PostgreSQL `VERIFY_FULL` is the explicit verified-TLS mode for that driver. Do not classify intentional plaintext/private-network compatibility as an authentication bypass by itself. Do report silent downgrade from an explicitly selected secure mode, credential disclosure where the API/configuration claims protection, peer-identity verification bypass, or code that treats an unauthenticated/plaintext channel as stronger than its documented guarantee. Separately, continue treating authenticated peers as lower-trust data sources: a compromised backend, database, Redis server, or MQTT broker may send hostile but correctly authenticated content, which must still be schema-validated, authorized, and bounded before privileged callbacks or persistence. @@ -180,6 +180,19 @@ Search for: If authentication is intentionally the consuming plugin's responsibility, document that boundary rather than inventing a missing SimpleAPI contract. +## Command dispatch and authorization + +Command routing is a security boundary when a consuming plugin exposes `CommandHandler` to ordinary players or non-player senders. Review the full gate before `execute` runs: + +- `hasPerm` and multi-permission parsing must enforce the intended permission for the actual sender; +- `allowConsole` / `forceConsole` and player-vs-non-player checks must not let RCON, command blocks, proxy senders, or other non-player sources inherit unintended console authority; +- argument-shape checks, special placeholders such as player selectors, and tab-completion helpers must not widen the action beyond what the permission authorizes; +- authorization must be rechecked where delayed/asynchronous execution creates a meaningful stale-permission or stale-target window; +- aliases or alternate dispatch paths must not bypass sender-type or permission gates; +- permission denial and malformed arguments must fail before privileged consumer callbacks execute. + +`CommandHandler.runCommand` currently performs argument checks, sender-type gating, and `hasPerm` before scheduling `execute` asynchronously. Treat regressions that bypass those gates, execute before authorization, or apply a weaker gate on an alternate path as security-relevant when the callback performs privileged work. + ## Concurrency, scheduling and lifecycle SimpleAPI is reused on Bukkit/Paper/Folia, proxies, and neutral/native contexts. @@ -288,8 +301,9 @@ SimpleAPI strongly values drop-in and API compatibility. Do not classify public 11. Replace, relay, replay, or disclose an HTTP connection code before enrollment and verify the implementation relies only on the explicitly trusted out-of-band delivery channel, code expiry, single-use semantics, identity binding, and pinned certificate data. 12. Create/load every persisted cryptographic secret under permissive umask and mixed local-account conditions; verify paths that promise private storage actually enforce it, and identify legacy paths such as `EncryptionHandler` that do not. 13. Rebuild from the same source while varying Maven repository availability, mutable snapshot contents, and transitive resolution; verify reviewed/released artifacts cannot silently substitute different shaded runtime bytes without detection. -14. Place an active network observer or malicious endpoint between each non-HTTP transport and its configured peer; verify plaintext/optional-TLS modes are classified according to their real guarantees, secure modes cannot silently downgrade, credentials are protected when promised, and unauthenticated encryption is never mistaken for peer identity or message authenticity. -15. Enable and disable bStats/telemetry repeatedly, inspect every outbound field and custom chart, and verify opt-out is respected, only documented/minimized metadata leaves the server, lower-trust data cannot inject secrets or unbounded values, and telemetry failures remain isolated. +14. Place an active network observer or malicious endpoint between each non-HTTP transport and its configured peer; verify plaintext/optional-TLS modes are classified according to their real guarantees, secure modes cannot silently downgrade, credentials are protected when promised, and legacy `EncryptionHandler` AES is never mistaken for authenticated or modern semantic confidentiality. +15. Exercise `CommandHandler` as a player, console, RCON/command-block-like non-player sender, and through aliases/alternate paths; verify permission, sender-type, argument, and stale-authorization checks hold before every privileged callback. +16. Enable and disable bStats/telemetry repeatedly, inspect every outbound field and custom chart, and verify opt-out is respected, only documented/minimized metadata leaves the server, lower-trust data cannot inject secrets or unbounded values, and telemetry failures remain isolated. ## Scan calibration and severity From baa27ba796c91fcb83eae22b5656f9f565ff25ad Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 18:07:40 -0600 Subject: [PATCH 11/13] docs: add outbound request boundary and DoS thresholds --- docs/security-threat-model.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index d744225..ff68d88 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -249,6 +249,23 @@ Prioritize: Require a realistic caller path and concrete resource effect. +## Caller-selected outbound requests and SSRF + +Not all outbound HTTP requests are fixed third-party APIs. Some shared helpers accept or derive destinations from caller-controlled values, so a benign consuming plugin can accidentally turn player or remote input into a server-side request. + +Review helpers such as `SkullCache.getContent(String)`, texture/profile URL handling, and `SkullCacheHandler.changeApiProfileURL` for: + +- allowing only intended URI schemes and rejecting non-HTTP(S) schemes where network fetches are expected; +- blocking or explicitly scoping loopback, link-local, private, metadata-service, Unix/local, and other internal destinations when lower-trust input can reach the URL; +- validating every redirect hop rather than only the initial destination; +- preventing DNS/rebinding or hostname-resolution changes from bypassing destination policy where such policy is promised; +- bounding response bytes before materializing the body, plus connect/read/request deadlines; +- avoiding credential/header forwarding to a redirected or attacker-selected authority; +- keeping caller-selected URLs out of unbounded caches or other persistent high-cardinality state; +- distinguishing fixed operator/maintainer-selected APIs from destinations reachable from player/vote/remote input. + +A generic helper accepting an operator-supplied URL is not automatically SSRF. Security relevance depends on a realistic lower-trust path into the destination or on a helper contract that promises safe URL fetching. + ## Outbound telemetry and third-party egress Metrics/telemetry is an outbound trust boundary even when the destination is intentionally configured or built in. When bStats or another telemetry path is enabled, data leaves the operator-controlled server and is disclosed to a third party. @@ -303,15 +320,16 @@ SimpleAPI strongly values drop-in and API compatibility. Do not classify public 13. Rebuild from the same source while varying Maven repository availability, mutable snapshot contents, and transitive resolution; verify reviewed/released artifacts cannot silently substitute different shaded runtime bytes without detection. 14. Place an active network observer or malicious endpoint between each non-HTTP transport and its configured peer; verify plaintext/optional-TLS modes are classified according to their real guarantees, secure modes cannot silently downgrade, credentials are protected when promised, and legacy `EncryptionHandler` AES is never mistaken for authenticated or modern semantic confidentiality. 15. Exercise `CommandHandler` as a player, console, RCON/command-block-like non-player sender, and through aliases/alternate paths; verify permission, sender-type, argument, and stale-authorization checks hold before every privileged callback. -16. Enable and disable bStats/telemetry repeatedly, inspect every outbound field and custom chart, and verify opt-out is respected, only documented/minimized metadata leaves the server, lower-trust data cannot inject secrets or unbounded values, and telemetry failures remain isolated. +16. Feed lower-trust URLs through skull/profile/custom outbound-fetch helpers, including loopback/private/link-local/metadata targets, redirects, hostile DNS, large bodies, and unusual schemes; verify destination and response bounds hold before data is fetched or cached. +17. Enable and disable bStats/telemetry repeatedly, inspect every outbound field and custom chart, and verify opt-out is respected, only documented/minimized metadata leaves the server, lower-trust data cannot inject secrets or unbounded values, and telemetry failures remain isolated. ## Scan calibration and severity Critical: ordinary-player or remote input reaches arbitrary JVM code execution, arbitrary host/plugin file write, or SQL syntax capable of modifying unrelated data through a SimpleAPI helper contract. -High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS/peer-identity verification bypass despite an explicitly selected verified mode; exposure of reusable network credentials or cryptographic keys to an on-path observer when the configured mode promises their protection; exposure of reusable cryptographic keys or HTTP client/server credentials to an unrelated local principal where private storage is expected; unauthorized local modification of security-critical configuration/state that redirects or weakens a protected connection or identity boundary; repeatable cross-user/state corruption or resource exhaustion affecting the server. +High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS/peer-identity verification bypass despite an explicitly selected verified mode; exposure of reusable network credentials or cryptographic keys to an on-path observer when the configured mode promises their protection; exposure of reusable cryptographic keys or HTTP client/server credentials to an unrelated local principal where private storage is expected; unauthorized local modification of security-critical configuration/state that redirects or weakens a protected connection or identity boundary; SSRF reaching sensitive internal/metadata/admin services with meaningful impact; resource exhaustion only when it is unbounded or strongly amplified, produces a sustained server-wide outage/watchdog/heap/disk failure at a practical attacker cost, or creates comparable cross-tenant impact. -Medium: parser/serialization ambiguity with a security-sensitive consumer; bounded but practical database or queue DoS; meaningful credential disclosure to limited readers; unintended telemetry disclosure of sensitive server/plugin/player data to a third party; lifecycle races causing occasional duplicate or lost privileged operations. +Medium: parser/serialization ambiguity with a security-sensitive consumer; bounded and recoverable database/queue/worker DoS that causes meaningful stalls, dropped work, or temporary availability loss but does not meet the High sustained-outage/amplification threshold; meaningful credential disclosure to limited readers; constrained SSRF with limited reachable impact; unintended telemetry disclosure of sensitive server/plugin/player data to a third party; lifecycle races causing occasional duplicate or lost privileged operations. Low: defense-in-depth hardening, minor log/path disclosure, compatibility-only TLS legacy behavior, generic dependency-hygiene concerns without a concrete artifact-substitution path, or generic API misuse requiring a fully malicious installed plugin. From 9890e5ae5ba007a10c6a1ab9c54ed62b818e8728 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 18:18:33 -0600 Subject: [PATCH 12/13] docs: add bootstrap entropy and event authorization targets --- docs/security-threat-model.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index ff68d88..d247f43 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -59,6 +59,8 @@ The copy/paste HTTP connection code is bootstrap trust material. Its embedded MA Treat interception, replacement, relay, disclosure, replay-before-consumption, and expiry handling of the connection code as part of this out-of-band bootstrap boundary. Do not blame the HTTP transport for an attacker who already controls that trusted delivery channel, but do report cases where the implementation accepts an expired/replayed/wrong-server code, fails to bind the resulting certificate to the advertised identity, or leaks the code/token outside that channel. +Bootstrap credentials must also be **unpredictable**, not merely secret in transit. Review enrollment tokens, challenges, credential-generation keys, and related one-time secrets for CSPRNG-backed generation, sufficient entropy/length, no predictable counters/timestamps/weak PRNG fallback, appropriate key-generation strength, and constant-time comparison where secret equality is checked. Current `HttpTransportSecrets.randomToken()` uses 32 random bytes from `SecureRandom`, `randomBytes` rejects very short secrets, and `constantTimeEquals` uses `MessageDigest.isEqual`; treat regressions that weaken those properties as security-relevant even if the connection code itself is never intercepted. + ### Local OS principals and security-critical persisted state Other local OS accounts/processes that do **not** already run as the Minecraft server account are a distinct lower-trust boundary for security-critical persisted state, including both secrets and configuration that controls trust decisions. Same-UID malicious plugin code is outside meaningful filesystem isolation, but unrelated local principals should not be able to read reusable credentials/keys **or modify** operator-owned configuration and state in ways that redirect connections, weaken TLS/authentication, change trusted endpoints, alter identity bindings, or change executable/runtime behavior. @@ -193,6 +195,21 @@ Command routing is a security boundary when a consuming plugin exposes `CommandH `CommandHandler.runCommand` currently performs argument checks, sender-type gating, and `hasPerm` before scheduling `execute` asynchronously. Treat regressions that bypass those gates, execute before authorization, or apply a weaker gate on an alternate path as security-relevant when the callback performs privileged work. +## Platform-event authorization helpers + +Some SimpleAPI helpers synthesize Bukkit events so downstream protection plugins can decide whether a player-requested world action is allowed. Those event results are an authorization boundary, not just an API convenience. + +Review helpers such as `PlayerUtils.canBreakBlock` and `PlayerUtils.canInteract` for: + +- constructing the event with the **actual player, block, action, item, face, and world context** that will be used by the real operation; +- dispatching the protection event synchronously on the platform thread/context required by Bukkit/Paper/Folia before the protected side effect occurs; +- honoring every cancellation/result field that is authoritative for that event type, including explicit cancellation and relevant `Event.Result.DENY` states rather than checking only one field when another can veto the action; +- preventing a caller from checking one block/action/actor and then applying the privileged effect to another; +- avoiding asynchronous or stale check-then-act windows where region/claim/permission state can change before the side effect; +- ensuring alternate helper/compatibility paths do not skip the protection-event check. + +`canBreakBlock` currently fires `BlockBreakEvent` and checks cancellation. `canInteract` fires `PlayerInteractEvent` and currently checks `useItemInHand() == DENY`; review whether all cancellation/result states required by consuming protection plugins are preserved for the intended operation. A helper returning `true` despite a protection plugin's authoritative denial can become an ordinary-player authorization bypass in the consuming plugin. + ## Concurrency, scheduling and lifecycle SimpleAPI is reused on Bukkit/Paper/Folia, proxies, and neutral/native contexts. @@ -315,13 +332,14 @@ SimpleAPI strongly values drop-in and API compatibility. Do not classify public 8. Pass lower-trust class, method, or provider names through reflection and dynamic-loading helpers. 9. Shut down while file, SQL, or network tasks are accepted and verify no stale callback mutates replacement state. 10. Package the neutral/shared artifact and inspect signatures, annotations, static initializers, and service descriptors for unexpected platform linkage. -11. Replace, relay, replay, or disclose an HTTP connection code before enrollment and verify the implementation relies only on the explicitly trusted out-of-band delivery channel, code expiry, single-use semantics, identity binding, and pinned certificate data. +11. Replace, relay, replay, disclose, or attempt to guess an HTTP connection code/enrollment credential; verify the implementation relies on an authentic out-of-band channel, CSPRNG-backed high-entropy tokens, constant-time secret comparison where applicable, code expiry, single-use semantics, identity binding, and pinned certificate data. 12. Create/load every persisted cryptographic secret under permissive umask and mixed local-account conditions; verify paths that promise private storage actually enforce it, and identify legacy paths such as `EncryptionHandler` that do not. 13. Rebuild from the same source while varying Maven repository availability, mutable snapshot contents, and transitive resolution; verify reviewed/released artifacts cannot silently substitute different shaded runtime bytes without detection. 14. Place an active network observer or malicious endpoint between each non-HTTP transport and its configured peer; verify plaintext/optional-TLS modes are classified according to their real guarantees, secure modes cannot silently downgrade, credentials are protected when promised, and legacy `EncryptionHandler` AES is never mistaken for authenticated or modern semantic confidentiality. 15. Exercise `CommandHandler` as a player, console, RCON/command-block-like non-player sender, and through aliases/alternate paths; verify permission, sender-type, argument, and stale-authorization checks hold before every privileged callback. -16. Feed lower-trust URLs through skull/profile/custom outbound-fetch helpers, including loopback/private/link-local/metadata targets, redirects, hostile DNS, large bodies, and unusual schemes; verify destination and response bounds hold before data is fetched or cached. -17. Enable and disable bStats/telemetry repeatedly, inspect every outbound field and custom chart, and verify opt-out is respected, only documented/minimized metadata leaves the server, lower-trust data cannot inject secrets or unbounded values, and telemetry failures remain isolated. +16. Exercise `PlayerUtils.canBreakBlock` / `canInteract` with protection plugins that cancel or deny different event result fields; verify the exact actor/block/action is checked synchronously and every authoritative denial prevents the subsequent side effect. +17. Feed lower-trust URLs through skull/profile/custom outbound-fetch helpers, including loopback/private/link-local/metadata targets, redirects, hostile DNS, large bodies, and unusual schemes; verify destination and response bounds hold before data is fetched or cached. +18. Enable and disable bStats/telemetry repeatedly, inspect every outbound field and custom chart, and verify opt-out is respected, only documented/minimized metadata leaves the server, lower-trust data cannot inject secrets or unbounded values, and telemetry failures remain isolated. ## Scan calibration and severity From 2399cd1719eb5c62a7bcad27b28d111ddf4d0ad5 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 28 Sep 2026 18:26:46 -0600 Subject: [PATCH 13/13] docs: add value-request session authorization boundary --- docs/security-threat-model.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/docs/security-threat-model.md b/docs/security-threat-model.md index d247f43..2d70741 100644 --- a/docs/security-threat-model.md +++ b/docs/security-threat-model.md @@ -195,6 +195,23 @@ Command routing is a security boundary when a consuming plugin exposes `CommandH `CommandHandler.runCommand` currently performs argument checks, sender-type gating, and `hasPerm` before scheduling `execute` asynchronously. Treat regressions that bypass those gates, execute before authorization, or apply a weaker gate on an alternate path as security-relevant when the callback performs privileged work. +## Value-request session and callback authorization + +`ValueRequest` and its chat, sign, book, dialog, and inventory input paths can feed player-controlled values into callbacks that a consuming plugin may use to mutate privileged configuration or state. Treat the pending request itself as an authorization/session boundary, not merely as a UI convenience. + +Review each request/input method for: + +- binding a response to the exact player, active request instance, input method, and view/session that created it; +- for inventory-backed requests, accepting clicks only from the request's own top inventory rather than from the player's bottom inventory or another simultaneously opened view; +- validating fixed-choice selections against the request's allowed option set instead of trusting an item's display name or other client-influenced presentation data; +- respecting `allowCustom=false` consistently across inventory, sign, book, chat, and dialog fallbacks; +- consuming one-shot request state before invoking a privileged callback so double-clicks, duplicate events, replayed UI actions, or re-entrant callbacks cannot execute twice; +- cancelling and cleaning up pending contexts on close, disconnect, plugin disable/reload, request replacement, and input-method changes; +- preventing stale callbacks from an older request from mutating state after a newer request/session has replaced it; +- keeping callback execution on the required platform thread/context and revalidating downstream permissions/ownership where the callback performs a privileged action. + +Current `InventoryRequestManager` stores request context by player UUID and, on click, reads `event.getCurrentItem()`'s display name before invoking the callback. Treat exact-inventory binding and allowed-option validation as explicit review targets: a pending fixed-choice request must not accept an arbitrary renamed item from the player's own inventory as though it were one of the presented choices. + ## Platform-event authorization helpers Some SimpleAPI helpers synthesize Bukkit events so downstream protection plugins can decide whether a player-requested world action is allowed. Those event results are an authorization boundary, not just an API convenience. @@ -337,15 +354,16 @@ SimpleAPI strongly values drop-in and API compatibility. Do not classify public 13. Rebuild from the same source while varying Maven repository availability, mutable snapshot contents, and transitive resolution; verify reviewed/released artifacts cannot silently substitute different shaded runtime bytes without detection. 14. Place an active network observer or malicious endpoint between each non-HTTP transport and its configured peer; verify plaintext/optional-TLS modes are classified according to their real guarantees, secure modes cannot silently downgrade, credentials are protected when promised, and legacy `EncryptionHandler` AES is never mistaken for authenticated or modern semantic confidentiality. 15. Exercise `CommandHandler` as a player, console, RCON/command-block-like non-player sender, and through aliases/alternate paths; verify permission, sender-type, argument, and stale-authorization checks hold before every privileged callback. -16. Exercise `PlayerUtils.canBreakBlock` / `canInteract` with protection plugins that cancel or deny different event result fields; verify the exact actor/block/action is checked synchronously and every authoritative denial prevents the subsequent side effect. -17. Feed lower-trust URLs through skull/profile/custom outbound-fetch helpers, including loopback/private/link-local/metadata targets, redirects, hostile DNS, large bodies, and unusual schemes; verify destination and response bounds hold before data is fetched or cached. -18. Enable and disable bStats/telemetry repeatedly, inspect every outbound field and custom chart, and verify opt-out is respected, only documented/minimized metadata leaves the server, lower-trust data cannot inject secrets or unbounded values, and telemetry failures remain isolated. +16. Exercise every `ValueRequest` input method with fixed choices and privileged callbacks; attempt bottom-inventory clicks, renamed items, stale/replaced requests, double-click/replay, close/reopen, disconnect, and reload, and verify only the exact active request and allowed values can invoke the callback once. +17. Exercise `PlayerUtils.canBreakBlock` / `canInteract` with protection plugins that cancel or deny different event result fields; verify the exact actor/block/action is checked synchronously and every authoritative denial prevents the subsequent side effect. +18. Feed lower-trust URLs through skull/profile/custom outbound-fetch helpers, including loopback/private/link-local/metadata targets, redirects, hostile DNS, large bodies, and unusual schemes; verify destination and response bounds hold before data is fetched or cached. +19. Enable and disable bStats/telemetry repeatedly, inspect every outbound field and custom chart, and verify opt-out is respected, only documented/minimized metadata leaves the server, lower-trust data cannot inject secrets or unbounded values, and telemetry failures remain isolated. ## Scan calibration and severity Critical: ordinary-player or remote input reaches arbitrary JVM code execution, arbitrary host/plugin file write, or SQL syntax capable of modifying unrelated data through a SimpleAPI helper contract. -High: realistic lower-trust SQL injection; authentication/origin bypass in a transport that promises authenticated messages; TLS/peer-identity verification bypass despite an explicitly selected verified mode; exposure of reusable network credentials or cryptographic keys to an on-path observer when the configured mode promises their protection; exposure of reusable cryptographic keys or HTTP client/server credentials to an unrelated local principal where private storage is expected; unauthorized local modification of security-critical configuration/state that redirects or weakens a protected connection or identity boundary; SSRF reaching sensitive internal/metadata/admin services with meaningful impact; resource exhaustion only when it is unbounded or strongly amplified, produces a sustained server-wide outage/watchdog/heap/disk failure at a practical attacker cost, or creates comparable cross-tenant impact. +High: realistic lower-trust SQL injection; ordinary-player bypass of a value-request/session boundary that reaches a privileged configuration/state mutation; authentication/origin bypass in a transport that promises authenticated messages; TLS/peer-identity verification bypass despite an explicitly selected verified mode; exposure of reusable network credentials or cryptographic keys to an on-path observer when the configured mode promises their protection; exposure of reusable cryptographic keys or HTTP client/server credentials to an unrelated local principal where private storage is expected; unauthorized local modification of security-critical configuration/state that redirects or weakens a protected connection or identity boundary; SSRF reaching sensitive internal/metadata/admin services with meaningful impact; resource exhaustion only when it is unbounded or strongly amplified, produces a sustained server-wide outage/watchdog/heap/disk failure at a practical attacker cost, or creates comparable cross-tenant impact. Medium: parser/serialization ambiguity with a security-sensitive consumer; bounded and recoverable database/queue/worker DoS that causes meaningful stalls, dropped work, or temporary availability loss but does not meet the High sustained-outage/amplification threshold; meaningful credential disclosure to limited readers; constrained SSRF with limited reachable impact; unintended telemetry disclosure of sensitive server/plugin/player data to a third party; lifecycle races causing occasional duplicate or lost privileged operations.