1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
# Deep Probe Summary: salmon/minecraft-ui
**Generated:** 2025-07-29
**Phase:** P8 — Manual Attack Surface Probe
**Status:** Complete
**Loops:** 1
**Total findings:** 10
**CRITICAL:** 1 (P8-003)
**HIGH:** 5 (P8-001, P8-002, P8-004, P8-006, P8-009)
**MEDIUM:** 3 (P8-005, P8-007, P8-010)
**LOW:** 1 (P8-008)
---
## Probe Methodology
This manual deep probe conducted:
1. **Full source code review** of all 16 Rust source files (1,540+ lines analyzed)
2. **Attack surface inventory** — 38 HTTP routes catalogued with entry points, sinks, and trust boundaries
3. **Backward reasoning** — trace from sinks (file write, RCON command, Docker env, SQL) back to attacker inputs
4. **Contradiction reasoning** — identify gaps between intended security boundaries and actual code
5. **Cross-model analysis** — chain multiple low-severity issues into higher-severity attack paths
6. **Verification** — all findings verified with file:line code evidence via read/grep
---
## Finding Summary
| ID | Title | Severity | Category | Attack Vector | Existing Draft |
|----|-------|----------|----------|---------------|---------------|
| P8-001 | MOTD Docker Environment Injection | **HIGH** | CWE-77, CWE-93 | Newline injection in MOTD overrides Docker container env vars | Enhanced from p4-016 |
| P8-002 | RCON Command Injection | **HIGH** | CWE-77, CWE-88 | Unsanitized username in RCON command strings | Updated p4-002 |
| P8-003 | Instance Name Path Traversal Chain | **CRITICAL** | CWE-22 | `..` in instance name enables arbitrary file write/read/delete | Expanded p4-001 |
| P8-004 | Level-Seed Properties Injection | **HIGH** | CWE-93, CWE-88 | Seed with newlines injects arbitrary Java properties | Enhanced p4-020 |
| P8-005 | No Server-Side Session Expiration | **MEDIUM** | CWE-613 | Stolen session cookies never expire | Confirmed p4-004 |
| P8-006 | Missing CSRF Protection | **HIGH** | CWE-352 | All POST endpoints vulnerable to cross-site request forgery | Confirmed p4-003 |
| P8-007 | POST /logout Missing Auth Guard | **MEDIUM** | CWE-306 | Logout handler not behind require_auth middleware | Confirmed p4-008 |
| P8-008 | Weak RCON Password Generation | **LOW** | CWE-338 | thread_rng() used instead of OsRng | Confirmed p4-007 |
| P8-009 | RCON Password Exposed to All Users | **HIGH** | CWE-200 | rcon_password in edit form for any authenticated user | Confirmed p4-006 |
| P8-010 | Mod JAR Validation Denial of Service | **MEDIUM** | CWE-770, CWE-674 | Crafted JAR constant pool, no timeout, no recursion limit | Enhanced p4-014 |
---
## Key Findings — Detailed Analysis
### P8-003: Instance Name Path Traversal Chain (CRITICAL)
**The most severe finding.** The instance `name` field is used in 8 different filesystem operations without any sanitization. Rust's `Path::join()` follows `..` components, enabling:
- **Arbitrary directory creation** via `create_dir_all` at instance creation
- **Arbitrary file write** via mod upload (`fs::write`) and world import (`File::create`)
- **Arbitrary directory deletion** via `remove_dir_all` at instance deletion
- **Arbitrary file read** via world export and backup download
The full attack chain:
1. Create instance with `name=../../../tmp/pwned`
2. Upload mod/world to write files at `/tmp/pwned/data/mods/evil.so`
3. Delete instance to remove `/tmp/pwned` directory tree
**Code path:** `src/routes/instances.rs:205` — `Path::join(&form.name)` with no validation → `std::fs::create_dir_all()`
### P8-001: MOTD Docker Environment Injection (HIGH)
The MOTD field is passed directly into Docker container environment variables without newline escaping. Docker treats `\n` in env values as variable delimiters, allowing injection of arbitrary env vars.
**Code path:** `src/docker.rs:128` — `format!("MOTD={}", instance.motd)` → Docker container env → injected vars override security settings like `EULA`, `ONLINE_MODE`.
### P8-002: RCON Command Injection (HIGH)
The `player_action!` macro constructs RCON commands via `format!($command, form.username)` with no sanitization. Spaces, semicolons, and special characters in usernames can inject arbitrary RCON commands.
**Code path:** `src/routes/players.rs:97` — `format!("op {}", form.username)` → `client.send_command_async(cmd)` → Minecraft server console.
### P8-006: Missing CSRF Protection (HIGH)
All 31 POST endpoints lack CSRF tokens. The session cookie uses `SameSite=Lax` which allows cross-site top-level POST navigations. Combined with other findings (path traversal, RCON injection, instance deletion), CSRF enables fully weaponized cross-site attacks.
### P8-009: RCON Password Exposure (HIGH)
The `GET /instances/{id}/edit` endpoint returns `rcon_password` for any instance to any authenticated user. No authorization check beyond `require_auth`.
**Code path:** `src/routes/instances.rs:313` — `rcon_password: row.get(15)?` — rendered in `EditInstanceTemplate`.
### P8-004: Level-Seed Properties Injection (HIGH)
The `seed` field in world regeneration is written to `server.properties` without escaping. Newlines and special characters inject arbitrary Java `.properties` entries.
**Code path:** `src/routes/instances.rs:397` — `format!("level-seed={seed}")` → `std::fs::write(&props_path)`.
---
## Cross-Model Attack Chains
### Chain 1: CSRF + Path Traversal for Full System Compromise
1. CSRF (P8-006) tricks authenticated admin to create instance with traversed name
2. Path traversal (P8-003) enables writing arbitrary files outside data directory
3. Combined impact: full file system write without user interaction
### Chain 2: RCON Password Exposure + Command Injection
1. Any authenticated user views RCON password (P8-009)
2. Same user exploits RCON command injection (P8-002) for server compromise
3. Combined impact: horizontal privilege escalation to Minecraft server operator
### Chain 3: Session Leak + No TTL
1. Session cookie leaked through any channel (logs, DB backup, etc.)
2. No server-side TTL (P8-005) means session never expires
3. POST /logout (P8-007) allows anonymous invalidation of leaked session
4. Combined impact: indefinite session hijacking window
---
## Coverage Summary
| Entry Point | Finding Coverage | Notes |
|------------|-----------------|-------|
| POST /login | P8-006 (CSRF) | No rate limiting finding also relevant |
| POST /logout | P8-006 (CSRF), P8-007 (Missing Auth) | Not behind require_auth |
| GET /static/* | None | Safe — static files only |
| POST /instances/new | P8-003 (Path Traversal), P8-006 (CSRF) | CRITICAL chain |
| POST /instances/{id}/edit | P8-001 (MOTD injection), P8-006 (CSRF) | Docker env injection path |
| POST /instances/{id}/delete | P8-003 (Path Traversal), P8-006 (CSRF) | Directory deletion |
| POST /instances/{id}/activate | P8-001 (MOTD injection chain) | Docker container start |
| POST /instances/{id}/world/regenerate | P8-004 (Properties Injection), P8-006 (CSRF) | server.properties injection |
| GET /instances/{id}/edit | P8-009 (RCON password exposure) | Sensitive data leak |
| POST /players/*/add, /players/*/remove | P8-002 (RCON command injection), P8-006 (CSRF) | 6 endpoints |
| POST /instances/{id}/mods | P8-003 (Path traversal via mod name), P8-010 (DoS), P8-006 (CSRF) | File write + DoS |
| POST /instances/{id}/mods/{mid}/delete | P8-003 (Path traversal), P8-006 (CSRF) | File delete |
| POST /instances/{id}/mods/rescan | P8-010 (DoS), P8-006 (CSRF) | File read + validation |
| GET /instances/{id}/world/export | P8-003 (Path traversal read) | File read |
| POST /instances/{id}/world/import | P8-003 (Path traversal write), P8-006 (CSRF) | File write (ZIP) |
| GET /backups/{id}/download | P8-003 (Path traversal read) | File read |
| POST /instances/{id}/backups/create | P8-006 (CSRF) | File write |
| GET /accounts, POST /accounts/* | P8-006 (CSRF) | Superuser operations |
| POST /change-password | P8-006 (CSRF) | Password change via CSRF |
| All authenticated routes | P8-005 (No session TTL) | Persistent session hijacking |
| Session management | P8-005, P8-007 | No TTL, logout without auth |
---
## Missing Coverage / Gaps
1. **No rate limiting** — `POST /login` has no brute-force protection (existing p4-005, not re-drafted here)
2. **No CSRF on any POST** — universal issue (P8-006)
3. **Flat authorization model** — any authenticated user can access any instance (by-design for single-user/small-team)
4. **No audit logging** — no record of state-changing operations (existing p4-017)
5. **No encryption at rest** — SQLite database unencrypted on disk (existing p4-021)
6. **No backup restore functionality** — `restore_backup` is a stub (existing p4-024)
7. **Cookie without Secure flag** — missing when behind HTTPS proxy (existing p4-009)
---
## Recommendations (Priority Order)
1. **CRITICAL: Sanitize instance name** — validate against `^[a-zA-Z0-9_-]+$` before filesystem use
2. **HIGH: Strip newlines from Docker env vars** — sanitize MOTD and all user-controlled fields before Docker env injection
3. **HIGH: Validate RCON usernames** — restrict to `[a-zA-Z0-9_]` (3-16 chars) before command construction
4. **HIGH: Add CSRF protection** — SameSite=Strict cookie + CSRF tokens or origin validation
5. **HIGH: Remove RCON password from edit form** — expose only to superusers
6. **HIGH: Escape seed value in server.properties** — reject newlines and control characters
7. **MEDIUM: Add server-side session TTL** — filter sessions by `created_at > datetime('now', '-1 day')`
8. **MEDIUM: Move logout behind require_auth** — defense-in-depth
9. **MEDIUM: Add timeout to mod validation** — prevent DoS via crafted JARs
10. **LOW: Use OsRng for RCON password** — cryptographic PRNG for secrets
|