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
|
# Architecture Entrypoints Inventory
**Target:** salmon/minecraft-ui
**Generated:** 2025-07-29
**Phase:** P3
---
## Public Routes (No Auth Required)
| # | Method | Path | Handler | Source file | Parameters | Attacker-controlled sources |
|---|--------|------|---------|-------------|------------|---------------------------|
| 1 | GET | `/login` | `login_page` | src/routes/mod.rs:43 | None | None |
| 2 | POST | `/login` | `authenticate` | src/auth.rs:34 | `username`, `password` (Form) | `username`, `password` strings |
| 3 | POST | `/logout` | `logout` | src/auth.rs:130 | Cookie header (optional) | Session ID from cookie |
| 4 | GET | `/static/*` | `ServeDir` | src/routes/mod.rs:28 | File path | Static file path (ServeDir) |
## Protected Routes (Auth Required via `require_auth` middleware)
### Dashboard
| # | Method | Path | Handler | Source file | Key inputs |
|---|--------|------|---------|-------------|------------|
| 5 | GET | `/` | `dashboard` | src/routes/dashboard.rs:19 | Session cookie → CurrentUser |
### Instance Management
| # | Method | Path | Handler | Source file | Key inputs |
|---|--------|------|---------|-------------|------------|
| 6 | GET | `/instances` | `list_instances` | src/routes/instances.rs:44 | None |
| 7 | GET | `/instances/new` | `create_form` | src/routes/instances.rs:70 | None |
| 8 | POST | `/instances/new` | `create_instance` | src/routes/instances.rs:87 | `name`, `version`, `server_type`, `world_source`, `seed`, `memory_mb`, `difficulty`, `gamemode`, `max_players`, `pvp`, `motd` |
| 9 | GET | `/instances/{id}/edit` | `edit_form` | src/routes/instances.rs:129 | Path: `id` (i64) |
| 10 | POST | `/instances/{id}/edit` | `edit_instance` | src/routes/instances.rs:176 | Path: `id`; Form: `difficulty`, `gamemode`, `max_players`, `pvp`, `whitelist_enabled`, `motd`, `memory_mb` |
| 11 | POST | `/instances/{id}/delete` | `delete_instance` | src/routes/instances.rs:198 | Path: `id` |
| 12 | POST | `/instances/{id}/activate` | `activate_instance` | src/routes/instances.rs:217 | Path: `id` |
| 13 | POST | `/instances/deactivate` | `deactivate_instance` | src/routes/instances.rs:278 | None |
### World Management
| # | Method | Path | Handler | Source file | Key inputs |
|---|--------|------|---------|-------------|------------|
| 14 | GET | `/instances/{id}/world/export` | `export_world` | src/routes/instances.rs:288 | Path: `id` |
| 15 | POST | `/instances/{id}/world/import` | `import_world` | src/routes/instances.rs:328 | Path: `id`; Multipart: ZIP file |
| 16 | POST | `/instances/{id}/world/regenerate` | `regenerate_world` | src/routes/instances.rs:360 | Path: `id`; Form: `seed` |
### Player Management
| # | Method | Path | Handler | Source file | Key inputs |
|---|--------|------|---------|-------------|------------|
| 17 | GET | `/players` | `manage_players` | src/routes/players.rs:28 | None |
| 18 | POST | `/players/whitelist/add` | `add_whitelist` | src/routes/players.rs:89 | `username` |
| 19 | POST | `/players/whitelist/remove` | `remove_whitelist` | src/routes/players.rs:89 | `username` |
| 20 | POST | `/players/op/add` | `add_op` | src/routes/players.rs:89 | `username` |
| 21 | POST | `/players/op/remove` | `remove_op` | src/routes/players.rs:89 | `username` |
| 22 | POST | `/players/ban/add` | `add_ban` | src/routes/players.rs:89 | `username` |
| 23 | POST | `/players/ban/remove` | `remove_ban` | src/routes/players.rs:89 | `username` |
### Backup Management
| # | Method | Path | Handler | Source file | Key inputs |
|---|--------|------|---------|-------------|------------|
| 24 | GET | `/instances/{id}/backups` | `list_backups` | src/routes/backups.rs:30 | Path: `id` |
| 25 | POST | `/instances/{id}/backups/create` | `create_backup` | src/routes/backups.rs:54 | Path: `id` |
| 26 | POST | `/backups/{id}/restore` | `restore_backup` | src/routes/backups.rs:88 | Path: `id` (STUB — no-op) |
| 27 | GET | `/backups/{id}/download` | `download_backup` | src/routes/backups.rs:93 | Path: `id` |
### Mod Management
| # | Method | Path | Handler | Source file | Key inputs |
|---|--------|------|---------|-------------|------------|
| 28 | GET | `/instances/{id}/mods` | `list_mods` | src/routes/mods.rs:42 | Path: `id` |
| 29 | POST | `/instances/{id}/mods` | `upload_mod` | src/routes/mods.rs:86 | Path: `id`; Multipart: `.jar`/`.zip` file + filename |
| 30 | POST | `/instances/{id}/mods/{mod_id}/delete` | `delete_mod` | src/routes/mods.rs:188 | Path: `instance_id`, `mod_id` |
| 31 | POST | `/instances/{id}/mods/rescan` | `rescan_mods` | src/routes/mods.rs:163 | Path: `id` |
### Account Management (Superuser only — guarded in handler)
| # | Method | Path | Handler | Source file | Key inputs |
|---|--------|------|---------|-------------|------------|
| 32 | GET | `/accounts` | `manage_accounts` | src/routes/accounts.rs:60 | None |
| 33 | POST | `/accounts/create` | `create_account` | src/routes/accounts.rs:95 | `username`, `password`, `is_superuser` |
| 34 | POST | `/accounts/delete` | `delete_account` | src/routes/accounts.rs:111 | `id` |
| 35 | POST | `/accounts/set-password` | `set_password` | src/routes/accounts.rs:142 | `id`, `new_password` |
| 36 | POST | `/accounts/change-own-password` | `change_own_password_from_accounts` | src/routes/accounts.rs:163 | `current_password`, `new_password` |
### Password Change (accessible before password_change_required satisfied)
| # | Method | Path | Handler | Source file | Key inputs |
|---|--------|------|---------|-------------|------------|
| 37 | GET | `/change-password` | `change_password_page` | src/routes/mod.rs:58 | Session cookie → CurrentUser |
| 38 | POST | `/change-password` | `accounts::change_password` | src/routes/mod.rs:65 | Session cookie; Form: `current_password`, `new_password` |
---
## Attacker-Controlled Sources Summary
| Source category | Examples | Highest risk sink |
|-----------------|----------|-------------------|
| Form fields (strings) | `username`, `name`, `seed`, `motd` | SQLite INSERT/UPDATE (parametrized), RCON command (unsanitized) |
| Multipart file bytes | `.jar`/`.zip` uploads | Filesystem write via `std::fs::write` |
| Multipart filename | `field.file_name()` | Filesystem path construction |
| Path parameters | `id`, `instance_id`, `mod_id` | SQL queries (parametrized), filesystem paths (backup download) |
| Cookie header | `mcui_session` | Session lookup (parametrized) |
---
## High-Value Sinks
| Sink category | Locations | Risk |
|--------------|-----------|------|
| **Filesystem write** | `src/routes/mods.rs:98` (`std::fs::write`); `src/routes/instances.rs:210` (`std::fs::File::create`); `src/routes/backups.rs:72` (`std::fs::File::create`) | **HIGH** — arbitrary file write from mod upload |
| **Filesystem read** | `src/routes/backups.rs:106` (`std::fs::read`); `src/routes/instances.rs:293` (`std::fs::read`) | MEDIUM — arbitrary file read |
| **Docker control** | `src/docker.rs:62` (`start_container`); `src/docker.rs:106` (`stop_container`) | **HIGH** — container lifecycle |
| **RCON command** | `src/routes/players.rs:89` (`client.send_command_async(cmd)`); `src/routes/instances.rs:153` (`send_command_async`) | **HIGH** — Minecraft server control |
| **SQL execution** | All `execute()` and `query_row()` calls (parametrized) | LOW — parametrized |
| **TLS outbound** | `src/routes/instances.rs:280` (`reqwest::Client` → Mojang API) | LOW — trusted URL |
---
## Key Source Files
| File | Role | Security relevance |
|------|------|-------------------|
| `src/auth.rs` | Auth middleware, login/logout, session management | **CRITICAL** — auth boundary |
| `src/routes/mod.rs` | Router builder, route composition | **CRITICAL** — which routes are protected |
| `src/routes/mods.rs` | Mod upload, ZIP extraction, validation | **HIGH** — file write, parsing |
| `src/routes/instances.rs` | Instance CRUD, world import/export, container | **HIGH** — ZIP extraction, file ops |
| `src/routes/backups.rs` | Backup create/download/restore | **MEDIUM** — file read/write |
| `src/routes/players.rs` | RCON whitelist/op/ban commands | **MEDIUM** — RCON injection |
| `src/routes/accounts.rs` | Account CRUD, password change | **HIGH** — privilege management |
| `src/mods.rs` | JAR metadata + class-file validation | **HIGH** — parsing attacker-supplied JARs |
| `src/rcon.rs` | RCON protocol client | **MEDIUM** — Minecraft server control |
| `src/docker.rs` | Docker container lifecycle | **HIGH** — host-level operations |
| `src/db.rs` | Database schema + connection | **MEDIUM** — schema design |
| `src/config.rs` | Configuration loading | **MEDIUM** — initial creds |
| `src/properties.rs` | .properties file reader | **LOW** |
|