T09 · Insecure Skill Coding Practices
Error
- Location
- git_federation_searcher.py:258
- Finding
- Shell Command Injection Through the SearXNG Fallback Query<![CDATA[ ## Vulnerability Details **File Location**: `git_federation_searcher.py:258-260` **Vulnerability Type**: OS command injection **Risk Level**: High ### Vulnerable Code ```python search_query = f"site:codeberg.org OR site:gitea.com OR site:notabug.org {query}" cmd = f'SEARXNG_URL=http://127.0.0.1:8080 python3 /root/.openclaw/workspace/skills/searxng-bangs/scripts/search.py "{search_query}" --num 10' result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30) ``` ### Technical Analysis The `query` value originates from a command-line argument or Telegram command and is interpolated directly into a shell command. The command is then passed to `subprocess.run` with `shell=True`. The surrounding double quotation marks do not provide safe shell escaping. An attacker can include a closing quote followed by shell operators, command substitutions, redirections, or other shell syntax. Because the operating-system shell parses the resulting string, attacker-controlled text can become executable shell syntax rather than remaining a single search argument. The vulnerable fallback is reached through `_web_search`, which is invoked when API searches return no results. The Telegram handler explicitly calls this method with the user-controlled query: ```python web_results = self.searcher._web_search(query) ``` ### Attack Path 1. An attacker submits a crafted `/gitsearch` query through the Telegram integration or supplies a crafted CLI query. 2. The query contains shell syntax capable of terminating the quoted search argument and appending another command. 3. Searches against the configured Git instances return no results, causing the application to invoke `_web_search`. 4. `_web_search` concatenates the malicious query into `cmd`. 5. `subprocess.run(..., shell=True)` passes the complete string to the system shell. 6. The injected command executes with the same operating-system identity and privileges as the Skill process. ### Impact ...[truncated 721 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Remove `shell=True` and pass every command argument as a separate list element: ```python import os search_query = ( "site:codeberg.org OR site:gitea.com OR site:notabug.org " + query ) env = os.environ.copy() env["SEARXNG_URL"] = "http://127.0.0.1:8080" result = subprocess.run( [ "python3", "/root/.openclaw/workspace/skills/searxng-bangs/scripts/search.py", search_query, "--num", "10", ], env=env, capture_output=True, text=True, timeout=30, check=False, ) ``` Additional hardening measures should include: - Apply a reasonable maximum length to search queries. - Avoid constructing executable strings from user input. - Execute the Skill under a dedicated, unprivileged operating-system account. - Restrict filesystem and network access using container or sandbox controls. - Add regression tests containing quotes, command substitutions, semicolons, redirections, and newline characters to verify that they remain literal query data. ]]>
