fix: prevent OS command injection in file manager (CWE-78) - #19
Open
poliakarmai wants to merge 1 commit into
Open
fix: prevent OS command injection in file manager (CWE-78)#19poliakarmai wants to merge 1 commit into
poliakarmai wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔍 Found by GSC — Git Security Checker
The file manager (
panel/routes/files.py) builds shell commands withsubprocess.run(..., shell=True)and interpolates user-controlled values directly into the command string.safe_path()only normalizes the path (os.path.normpath('/' + p)) — it does not escape shell metacharacters, and two endpoints (/api/files/search,/api/files/scan) skip it entirely.Vulnerability (CWE-78 — OS Command Injection)
/api/files/search?q=<...>— theqparameter is interpolated intogrep/findwith no sanitization at all./api/files/compress,/api/files/extract,/api/files/lint,/api/files/size,/api/files/properties—src/dst/path/outputpass throughsafe_path(), which does not neutralize;,$(...), backticks, or quotes./api/files/scan—pathis taken from the JSON body withoutsafe_path().An authenticated user can inject arbitrary shell commands (e.g.
q="; id; #"on the search endpoint), leading to remote command execution on the panel host.Fix
Replace
shell=Truestring commands with argument lists (shell=False) and pass the working directory viacwd=instead ofcd. This removes shell interpretation entirely, so no metacharacter can be injected.Files Changed
panel/routes/files.py— allsubprocess.run(shell=True, ...)calls converted to argument lists;scan_filenow appliessafe_path().📚 Understanding This Vulnerability
What is it?
OS command injection (CWE-78) happens when user input is concatenated into a shell command without escaping. An attacker who controls any interpolated value can append their own commands.
Why does it matter?
It is OWASP A03:2021 (Injection). A single injectable parameter turns into arbitrary code execution on the server — the attacker inherits the panel's privileges (often root). This is how many server control panels get fully compromised.
When does it happen?
subprocess.run(cmd, shell=True)with an f-string containing user input.shlex.quote()/ argument list.How to fix it properly?
shell=Falsewith a list of arguments — no shell, no injection surface.cwd=forcdandstderr=subprocess.DEVNULLfor2>/dev/null.shell=Trueis unavoidable, wrap every value inshlex.quote().🧠 Analogy
Telling a waiter "write whatever the customer says on the order form" vs. handing them a pre-printed form where only the fields can be filled in. An argument list is the pre-printed form — the customer can't rewrite the whole order.
📖 Further reading
🐛 Found by GSC — понимай код, а не принимай.