summaryrefslogtreecommitdiffstats
path: root/piolium/attack-surface/source-sink-flows-all-severities.md
diff options
context:
space:
mode:
Diffstat (limited to 'piolium/attack-surface/source-sink-flows-all-severities.md')
-rw-r--r--piolium/attack-surface/source-sink-flows-all-severities.md143
1 files changed, 143 insertions, 0 deletions
diff --git a/piolium/attack-surface/source-sink-flows-all-severities.md b/piolium/attack-surface/source-sink-flows-all-severities.md
new file mode 100644
index 0000000..d7f93da
--- /dev/null
+++ b/piolium/attack-surface/source-sink-flows-all-severities.md
@@ -0,0 +1,143 @@
1# Source-to-Sink Flow Paths (All Severities)
2
3Generated by manual structural extraction (codeql not available on this system).
4
5## Critical Flows
6
7### Flow C1: Instance Name Path Traversal → Arbitrary Directory Creation
8- **Source:** `POST /instances/new` → `CreateInstanceForm.name` (free text, no validation)
9- **Path:** `src/routes/instances.rs:165` → `form.name` → `src/routes/instances.rs:205` `.join(&form.name)` → `std::fs::create_dir_all()`
10- **Risk:** Attacker can create directories anywhere the webUI user has write access via `../` in instance name
11- **Control:** NO sanitization whatsoever on `form.name`
12- **CWE:** CWE-22 (Path Traversal)
13
14### Flow C2: Instance Name Path Traversal → Arbitrary Directory Deletion
15- **Source:** `POST /instances/{id}/delete` → name from DB (originally `form.name`, no sanitization)
16- **Path:** `src/routes/instances.rs:360` → `DELETE FROM instances WHERE id=?` → name from DB → `src/routes/instances.rs:392-393` `.join(&name)` → `std::fs::remove_dir_all()`
17- **Risk:** Attacker can delete directories anywhere via `../` in instance name
18- **Control:** Name stored in DB at creation time without sanitization
19- **CWE:** CWE-22 (Path Traversal)
20
21## High Severity Flows
22
23### Flow H1: RCON Command Injection via Player Username
24- **Source:** `POST /players/whitelist/add` → `PlayerAction.username` (free text)
25- **Path:** `src/routes/players.rs:93` → `form.username` → `src/routes/players.rs:97` `format!("whitelist add {}", form.username)` → `RconClient.send_command_async(cmd)`
26- **Risk:** Attacker can inject arbitrary RCON commands via username field (e.g., `foo; op attacker`)
27- **Control:** NO sanitization on `form.username`
28- **CWE:** CWE-77 (Command Injection), CWE-88 (Argument Injection)
29
30### Flow H2: RCON Command Injection via OP/Ban Username
31- **Source:** `POST /players/op/add` → `PlayerAction.username` (same for ban/pardon/deop)
32- **Path:** `src/routes/players.rs:90-98` → `player_action!` macro generates: `format!("op {}", form.username)` → `RconClient.send_command_async()`
33- **Risk:** Same as H1 — arbitrary RCON command injection
34- **CWE:** CWE-77, CWE-88
35
36### Flow H3: No Session Expiration/TTL Server-Side
37- **Source:** Any authenticated session
38- **Path:** Session stored in SQLite with `created_at` timestamp but **never checked** on authentication
39- **Risk:** Stolen session cookies remain valid indefinitely server-side
40- **CWE:** CWE-613 (Insufficient Session Expiration)
41
42### Flow H4: No CSRF Protection on Any POST Endpoint
43- **Source:** All POST endpoints
44- **Path:** No CSRF token validation anywhere in the application
45- **Risk:** Cross-site request forgery — any website can trigger state-changing operations
46- **CWE:** CWE-352 (Cross-Site Request Forgery)
47
48## Medium Severity Flows
49
50### Flow M1: Mod Filename After Directory Stripping Special Characters
51- **Source:** `POST /instances/{id}/mods` → multipart upload filename
52- **Path:** `field.file_name()` → `process_jar_upload()` → `Path::new(filename).file_name()` (strips dir) → `mods_dir.join(&safe_name)` → `std::fs::write()`
53- **Risk:** After directory stripping, filename may still contain special characters or Unicode normalization issues
54- **CWE:** CWE-22
55
56### Flow M2: World Import ZIP Extraction (Mitigated)
57- **Source:** `POST /instances/{id}/world/import` → multipart ZIP
58- **Path:** `zip::ZipArchive::new()` → `archive.by_index(i)` → `file.enclosed_name()` → `world_dir.join(p)` → `File::create()`
59- **Risk:** Zip slip partially mitigated by `enclosed_name()` but edge cases may exist
60- **CWE:** CWE-22
61
62### Flow M3: Backup Download Using Filename from DB
63- **Source:** `GET /backups/{id}/download` → `backup_id` path parameter
64- **Path:** `Path(backup_id)` → SQL SELECT filename → `backup_dir.join(&filename)` → `std::fs::read()`
65- **Risk:** If filename field in DB is manipulated, could read arbitrary files
66- **CWE:** CWE-22
67
68### Flow M4: Docker Container Environment Variable Injection
69- **Source:** `POST /instances/new` → various form fields
70- **Path:** `CreateInstanceForm` → SQL INSERT → Instance model → `docker.start_container(&instance)` → `ContainerConfig.env` includes instance fields unescaped
71- **Risk:** User-controlled strings passed to Docker container environment
72- **CWE:** CWE-77
73
74### Flow M5: Level-Seed Injection into server.properties
75- **Source:** `POST /instances/{id}/world/regenerate` → `form.seed`
76- **Path:** `form.seed` → `format!("level-seed={seed}")` → `std::fs::write(&props_path, ...)`
77- **Risk:** Seed string written directly to properties file; could corrupt configuration
78- **CWE:** CWE-93 (CRLF Injection)
79
80### Flow M6: Weak RCON Password Generation
81- **Source:** `generate_rcon_password()` called during instance creation
82- **Path:** `rand::thread_rng()` → 16-char alphanumeric → stored in DB
83- **Risk:** Not cryptographically secure RNG for password generation
84- **CWE:** CWE-338 (Use of Cryptographically Weak PRNG)
85
86### Flow M7: RCON Password Exposed to All Authenticated Users
87- **Source:** `GET /instances/{id}/edit` template
88- **Path:** SQL SELECT includes `rcon_password` → `EditInstanceTemplate` → rendered in HTML
89- **Risk:** Any authenticated user can see the RCON password
90- **CWE:** CWE-200 (Information Exposure)
91
92### Flow M8: Logout Handler Without Auth Middleware
93- **Source:** `POST /logout` (registered on outer router, not behind `require_auth`)
94- **Path:** Cookie header parsed → `DELETE FROM sessions WHERE id = ?`
95- **Risk:** Anonymous requests can delete sessions if session ID is known/guessed
96- **CWE:** CWE-306 (Missing Authentication)
97
98### Flow M9: No Rate Limiting on Login
99- **Source:** `POST /login`
100- **Path:** Infinite brute-force attempts possible
101- **Risk:** Account enumeration and password brute-force
102- **CWE:** CWE-307 (Improper Restriction of Excessive Authentication Attempts)
103
104### Flow M10: Cookie Without Secure Flag
105- **Source:** Login sets cookie
106- **Path:** `format!("{SESSION_COOKIE}={session_id}; Path=/; HttpOnly; Max-Age=86400; SameSite=Lax")`
107- **Risk:** Cookie transmitted over HTTP (missing Secure flag)
108- **CWE:** CWE-614 (Sensitive Cookie in HTTPS Without Secure Attribute)
109
110## Low Severity Flows
111
112### Flow L1: Mod JAR Parsing Denial of Service
113- **Source:** `POST /instances/{id}/mods` → uploaded JAR
114- **Path:** `validate_mod()` → `ZipArchive::new()` → `scan_jar_for_side()` → constant pool parsing
115- **Risk:** Crafted JAR with malicious constant pool could cause OOM or infinite loop
116- **CWE:** CWE-770 (Allocation of Resources Without Limits)
117
118### Flow L2: Recursive ZIP Extraction Without Depth Limit
119- **Source:** `POST /instances/{id}/mods` → ZIP containing JAR (which is also a ZIP)
120- **Path:** `process_zip_upload()` → extracts JAR → `process_jar_upload()` → `validate_mod()` opens JAR as ZIP again
121- **Risk:** No depth counter; nested ZIP-in-JAR could cause resource exhaustion
122- **CWE:** CWE-674 (Uncontrolled Recursion)
123
124### Flow L3: Backup Restore is No-Op
125- **Source:** `POST /backups/{id}/restore`
126- **Path:** Looks up (instance_id, _filename) from DB, then returns redirect without restoring
127- **Risk:** Backup restore functionality is implemented as a stub; users think data is restored
128- **CWE:** CWE-1039 (Automated Recognition Mechanism with Inadequate Detection)
129
130### Flow L4: No Audit Logging
131- **Source:** All state-changing operations
132- **Path:** No logging of who performed what action
133- **Risk:** No accountability or forensic evidence for security incidents
134
135### Flow L5: ThreadRng Used for Password Generation
136- **Source:** `src/routes/instances.rs:530`
137- **Path:** `rand::thread_rng()` → 36^16 password space
138- **Risk:** Predictable RNG seed may make RCON password guessable
139
140### Flow L6: Cookie Splitting Parsing is Naive
141- **Source:** `src/auth.rs:107` and `src/auth.rs:182`
142- **Path:** `raw_cookies.split(';')` then `split_once('=')`
143- **Risk:** If cookie value contains `=` or `;`, parsing may be confused