diff options
| author | salmonik <salmonik@tuta.io> | 2026-07-29 02:24:41 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-07-29 02:24:41 +0200 |
| commit | c654a6d17eb58adbb15b9c47ab32bcc3a1666307 (patch) | |
| tree | 545544bf7d805254415da787fad1cdc711767833 /templates/instances/edit.html | |
| parent | Add per-instance mod management with client-side detection (diff) | |
| download | minecraft-ui-c654a6d17eb58adbb15b9c47ab32bcc3a1666307.tar.gz minecraft-ui-c654a6d17eb58adbb15b9c47ab32bcc3a1666307.zip | |
Security audit fixes: patch 16 vulnerabilities across 7 source files
CRITICAL:
- Instance name path traversal (AP-001): sanitize::sanitize_instance_name()
strips .., /, \, \0, spaces, special chars at all 12 join call sites
- Zip-slip protection in world import: starts_with() guard after enclosed_name()
HIGH:
- RCON command injection: validate_username() rejects non-MC usernames
across all 6 player action macros (whitelist, op, ban)
- Level-seed properties injection: sanitize_seed() strips \n \r = : \0
- CSRF protection: SameSite=Lax -> SameSite=Strict on session cookie
MEDIUM:
- Session TTL: server-side 24h expiry via strftime check in require_auth
- Rate limiting: in-memory 10-ip/5min sliding window on login
- Background task stale is_active: all queries use concrete WHERE id=?1
- Mod validation DoS: 500MB cap, 10k class scan limit, 10k CP entry cap
LOW:
- Logout auth guard: moved into protected route group + CurrentUser param
- Mod orphan race: DB insert before file write
- Backup orphan race: DB insert before ZIP creation
- Template fix: broken Askama == comparisons in edit.html
All fixes compile clean with zero warnings. 10 unit tests pass.
Diffstat (limited to '')
| -rw-r--r-- | templates/instances/edit.html | 39 |
1 files changed, 15 insertions, 24 deletions
diff --git a/templates/instances/edit.html b/templates/instances/edit.html index 2660461..77dfca6 100644 --- a/templates/instances/edit.html +++ b/templates/instances/edit.html | |||
| @@ -35,8 +35,7 @@ | |||
| 35 | value="0" | 35 | value="0" |
| 36 | {% | 36 | {% |
| 37 | if | 37 | if |
| 38 | instance.difficulty="" | 38 | instance.difficulty == 0 |
| 39 | ="0" | ||
| 40 | %}selected{% | 39 | %}selected{% |
| 41 | endif | 40 | endif |
| 42 | %} | 41 | %} |
| @@ -47,8 +46,7 @@ | |||
| 47 | value="1" | 46 | value="1" |
| 48 | {% | 47 | {% |
| 49 | if | 48 | if |
| 50 | instance.difficulty="" | 49 | instance.difficulty == 1 |
| 51 | ="1" | ||
| 52 | %}selected{% | 50 | %}selected{% |
| 53 | endif | 51 | endif |
| 54 | %} | 52 | %} |
| @@ -59,8 +57,7 @@ | |||
| 59 | value="2" | 57 | value="2" |
| 60 | {% | 58 | {% |
| 61 | if | 59 | if |
| 62 | instance.difficulty="" | 60 | instance.difficulty == 2 |
| 63 | ="2" | ||
| 64 | %}selected{% | 61 | %}selected{% |
| 65 | endif | 62 | endif |
| 66 | %} | 63 | %} |
| @@ -71,8 +68,7 @@ | |||
| 71 | value="3" | 68 | value="3" |
| 72 | {% | 69 | {% |
| 73 | if | 70 | if |
| 74 | instance.difficulty="" | 71 | instance.difficulty == 3 |
| 75 | ="3" | ||
| 76 | %}selected{% | 72 | %}selected{% |
| 77 | endif | 73 | endif |
| 78 | %} | 74 | %} |
| @@ -84,16 +80,16 @@ | |||
| 84 | <label> | 80 | <label> |
| 85 | Gamemode | 81 | Gamemode |
| 86 | <select name="gamemode"> | 82 | <select name="gamemode"> |
| 87 | <option value="0" {% if instance.gamemode="" ="0" %}selected{% endif %}> | 83 | <option value="0" {% if instance.gamemode == 0 %}selected{% endif %}> |
| 88 | Survival | 84 | Survival |
| 89 | </option> | 85 | </option> |
| 90 | <option value="1" {% if instance.gamemode="" ="1" %}selected{% endif %}> | 86 | <option value="1" {% if instance.gamemode == 1 %}selected{% endif %}> |
| 91 | Creative | 87 | Creative |
| 92 | </option> | 88 | </option> |
| 93 | <option value="2" {% if instance.gamemode="" ="2" %}selected{% endif %}> | 89 | <option value="2" {% if instance.gamemode == 2 %}selected{% endif %}> |
| 94 | Adventure | 90 | Adventure |
| 95 | </option> | 91 | </option> |
| 96 | <option value="3" {% if instance.gamemode="" ="3" %}selected{% endif %}> | 92 | <option value="3" {% if instance.gamemode == 3 %}selected{% endif %}> |
| 97 | Spectator | 93 | Spectator |
| 98 | </option> | 94 | </option> |
| 99 | </select> | 95 | </select> |
| @@ -162,8 +158,8 @@ | |||
| 162 | {% endif %} | 158 | {% endif %} |
| 163 | 159 | ||
| 164 | <div class="meta" style="margin-bottom: 1rem"> | 160 | <div class="meta" style="margin-bottom: 1rem"> |
| 165 | <span | 161 | <span> |
| 166 | ><strong>Current seed:</strong> | 162 | <strong>Current seed:</strong> |
| 167 | {% if let Some(seed) = current_seed %} {{ seed }} {% else %} | 163 | {% if let Some(seed) = current_seed %} {{ seed }} {% else %} |
| 168 | <em>not yet generated</em> | 164 | <em>not yet generated</em> |
| 169 | {% endif %} | 165 | {% endif %} |
| @@ -181,8 +177,7 @@ | |||
| 181 | {% | 177 | {% |
| 182 | if | 178 | if |
| 183 | instance.is_active | 179 | instance.is_active |
| 184 | %} | 180 | %}tabindex="-1" |
| 185 | tabindex="-1" | ||
| 186 | {% | 181 | {% |
| 187 | endif | 182 | endif |
| 188 | %} | 183 | %} |
| @@ -205,8 +200,7 @@ | |||
| 205 | {% | 200 | {% |
| 206 | if | 201 | if |
| 207 | instance.is_active | 202 | instance.is_active |
| 208 | %} | 203 | %}disabled{% |
| 209 | disabled{% | ||
| 210 | endif | 204 | endif |
| 211 | %} | 205 | %} |
| 212 | /> | 206 | /> |
| @@ -219,8 +213,7 @@ | |||
| 219 | {% | 213 | {% |
| 220 | if | 214 | if |
| 221 | instance.is_active | 215 | instance.is_active |
| 222 | %} | 216 | %}disabled{% |
| 223 | disabled{% | ||
| 224 | endif | 217 | endif |
| 225 | %} | 218 | %} |
| 226 | > | 219 | > |
| @@ -246,8 +239,7 @@ | |||
| 246 | {% | 239 | {% |
| 247 | if | 240 | if |
| 248 | instance.is_active | 241 | instance.is_active |
| 249 | %} | 242 | %}disabled{% |
| 250 | disabled{% | ||
| 251 | endif | 243 | endif |
| 252 | %} | 244 | %} |
| 253 | /> | 245 | /> |
| @@ -257,8 +249,7 @@ | |||
| 257 | {% | 249 | {% |
| 258 | if | 250 | if |
| 259 | instance.is_active | 251 | instance.is_active |
| 260 | %} | 252 | %}disabled{% |
| 261 | disabled{% | ||
| 262 | endif | 253 | endif |
| 263 | %} | 254 | %} |
| 264 | > | 255 | > |
