T09 · Insecure Skill Coding Practices
- Location
git_federation_searcher.py:258- Finding
Shell Command Injection Through the SearXNG Fallback Query
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill largely matches its search purpose, but it contains exploitable command execution and under-scoped network and credential handling risks that need review before installation.
Do not install this skill in a shared, bot-accessible, or privileged environment unless the shell=True fallback is removed, Telegram admin checks are added, custom instance URLs are restricted, and API tokens are moved out of plaintext config and URL parameters. There is no clear evidence of intentional exfiltration or destructive behavior, but the current implementation exposes high-impact abuse paths.
git_federation_searcher.py:258Shell Command Injection Through the SearXNG Fallback Query
git_federation_searcher.py:108Unrestricted Custom Instance URLs Enable Server-Side Request Forgery
git_federation_searcher.py:96Git API Tokens Are Stored in Plaintext and Transmitted in URL Query Strings
The tool invocation at this line directly incorporates attacker-controlled query content into a shell command, allowing parameter abuse to become full command injection. Because this is in a search skill where arbitrary user input is expected, the context makes exploitation especially straightforward and severe.
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)
if result.returncode == 0:
data = json.loads(result.stdout)
The skill advertises capabilities consistent with network, shell, file read, and file write access, but it does not declare any explicit tool scope or permissions boundaries in the skill manifest. Because the skill supports adding custom instances and API token use, the lack of scoped permissions increases the risk of unintended outbound requests, unsafe command execution paths, or writing sensitive configuration data without clear operator control.
The skill persists instance configuration and API tokens under a local workspace path, which is more sensitive behavior than a simple transient search utility. In a multi-skill or shared environment, undisclosed credential storage increases the risk of token exposure and violates least surprise for users.
API tokens supplied for private instances are serialized to instances.json in plaintext without warning, encryption, or access controls visible in the code. If the workspace is readable by other processes, users, backups, or logs, those tokens can be stolen and reused against private Git services.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def _detect_type(self, url: str) -> str:
"""Try to detect Git instance type"""
try:
result = subprocess.run(
["curl", "-s", "-m", "5", f"{url}/api/v1/version"],
capture_output=True,
text=True
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
# Try GitLab
try:
result = subprocess.run(
["curl", "-s", "-m", "5", f"{url}/api/v4/version"],
capture_output=True,
text=True
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def _test_instance(self, instance: GitInstance) -> bool:
"""Test if instance is reachable"""
try:
result = subprocess.run(
["curl", "-s", "-m", "5", "-o", "/dev/null", "-w", "%{http_code}",
f"{instance.url}/api/v1/version"],
capture_output=True,
User queries and optional access tokens are sent to remote Git instances, and the tokens are included in URL query strings instead of headers. This not only creates an undisclosed data-sharing/privacy issue but also increases leakage risk through process listings, HTTP logs, intermediary infrastructure, and server access logs.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if instance.api_token:
url += f"&access_token={instance.api_token}"
result = subprocess.run(
["curl", "-s", "-m", "10", url],
capture_output=True,
text=True
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if instance.api_token:
url += f"&access_token={instance.api_token}"
result = subprocess.run(
["curl", "-s", "-m", "10", url],
capture_output=True,
text=True
When primary searches fail, the skill silently forwards the user's query to a SearXNG service through an external script without warning. In context, this is riskier because it changes the destination and handling of user data unexpectedly and is implemented via a shell command that adds additional exploitation surface.
The fallback behavior expands the skill's capabilities from repository-instance search into arbitrary execution of another local script via a shell. In context, that broader execution path matters because it increases attack surface and creates an unexpected trust boundary crossing, especially when coupled with unsanitized user input.
This builds a shell command containing the user-controlled query and executes it with shell=True, which enables command injection. An attacker can break out of the quoted search term and run arbitrary shell commands in the skill's execution context, making this materially more dangerous than the skill's stated search functionality.
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)
if result.returncode == 0:
data = json.loads(result.stdout)
The file exposes a Telegram bot command surface for the skill, which materially expands the attack surface beyond simple search functionality described in the skill metadata. A chat-driven interface can be invoked by any user the bot serves, and it forwards user-controlled input into backend search and instance-management logic, increasing the chance of misuse, data exposure, or abuse of network capabilities.
The /gitadd command allows users to add arbitrary Git instance URLs through chat, effectively exposing administrative configuration and outbound network access to untrusted users. If add_instance performs connectivity checks or stores the instance for later searches, this can enable SSRF, internal network probing, persistence of attacker-controlled endpoints, and expansion of future search activity toward malicious or private hosts.
The manifest description in _meta.json narrows the skill to searching self-hosted Git instances '(Gitea, Forgejo, GitLab)'. However, the provided skill context states it also aggregates results from public services like Codeberg.org, Gitea.com, OpenDev, NotABug, and Gitdab and supports fallback to SearXNG web search, which is materially broader than the manifest text.
The skill emits user-facing strings such as "Git-Suche", "Ergebnisse", and other CLI messages exclusively in German. This imposes a specific language on users without offering a locale choice or documenting a justified region-specific constraint.
No suspicious patterns detected.