Back to skill

Security audit

clash-auto-switch

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent proxy auto-switching purpose, but it ships unsafe credential handling, injectable shell code, and elevated scheduled-task guidance that users should review before installing.

Install only after reviewing the scripts. Prefer the Python skill path with a unique local Clash secret, keep the controller bound to localhost, avoid passing secrets on command lines or committing them to config files, do not run scheduled tasks as administrator/root, and avoid the bundled shell scripts unless the hardcoded secret, injection bug, and `/tmp` state handling are fixed.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
clash-switch.sh:15
Finding
Hardcoded Clash Controller Credential<![CDATA[ ## Vulnerability Details **File Location**: `clash-switch.sh:15-17` and `clash-switch.sh:369-375`; duplicated in `clash-switch-v2.sh:16-18` **Vulnerability Type**: Hardcoded secret and credential disclosure **Risk Level**: High ### Vulnerable Code ```bash # 配置变量 CLASH_API="http://127.0.0.1:58871" CLASH_SECRET="6434ff5a-5b0f-4598-99ec-83ca96c77167" PROXY_URL="http://127.0.0.1:7890" ``` The original script also prints the credential in its help output: ```bash 配置: Clash API: ${CLASH_API} 代理地址: ${PROXY_URL} 控制密钥: ${CLASH_SECRET} ``` The enhanced script contains the same embedded credential: ```bash CLASH_API="http://127.0.0.1:58871" CLASH_SECRET="6434ff5a-5b0f-4598-99ec-83ca96c77167" PROXY_URL="http://127.0.0.1:7890" ``` ### Technical Analysis A reusable Clash API bearer credential is embedded directly in two distributed shell scripts. The secret is transmitted in the `Authorization` header when accessing the Clash controller and is additionally disclosed in the original script's help output. Anyone who can read the project files, package contents, shell history, support logs, or help output can recover the credential. If a Clash installation retains this credential and its external controller is reachable, the exposed value can authorize proxy enumeration and routing changes. ### Attack Path 1. An attacker downloads the public package or obtains a local copy of the scripts. 2. The attacker extracts the hardcoded `CLASH_SECRET`. 3. The attacker locates a Clash controller configured with that credential, such as an externally exposed controller or one reachable from the same host or network. 4. The attacker sends authenticated requests to `/proxies` to enumerate proxy groups and nodes. 5. The attacker issues authenticated `PUT` requests to change active proxy selections and influence the victim's network routing. ### Impact Assessment The credential grants the level of control exposed by the Clash external-controller API. Confirmed scr ...[truncated 287 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the embedded credential from both shell scripts and rotate it immediately wherever it has been used. 2. Read the secret from `CLASH_SECRET` or a dedicated configuration file rather than source code. 3. If a configuration file is used, require ownership by the executing user and permissions no broader than `0600`. 4. Remove the secret from all help, status, diagnostic, and log output. 5. Prevent accidental commits with secret-scanning hooks and CI checks. 6. Bind the Clash controller to loopback unless remote administration is explicitly required. 7. Use a unique credential per installation rather than a shared package-level default. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
clash-switch.sh:42
Finding
Arbitrary Python Code Execution Through Crafted Proxy Node Names<![CDATA[ ## Vulnerability Details **File Location**: `clash-switch.sh:42-46` **Vulnerability Type**: Code injection **Risk Level**: Critical ### Vulnerable Code ```bash # URL 编码函数 urlencode() { local string="$1" python3 -c "import urllib.parse; print(urllib.parse.quote('''$string'''))" 2>/dev/null || \ echo "$string" | sed 's/ /%20/g' } ``` The vulnerable function is reached with proxy names retrieved from the Clash API: ```bash test_proxy_delay() { local proxy_name="$1" local encoded_name=$(urlencode "$proxy_name") local delay=$(clash_api_get "/proxies/${encoded_name}/delay?timeout=5000&url=http://www.gstatic.com/generate_204" | jq -r '.delay' 2>/dev/null) ``` ### Technical Analysis The `urlencode` function inserts `$string` directly into Python source passed to `python3 -c`. Shell quoting does not make the resulting Python program safe. A proxy node name containing a terminating triple quote can escape the intended Python string and append attacker-selected Python statements. Proxy names are not inherently trusted. They can originate from imported proxy subscriptions or a compromised Clash controller. Normal auto-selection and latency-testing flows pass these names into `urlencode`, so no direct shell argument from the attacker is required. ### Attack Path 1. An attacker controls or compromises a proxy subscription, or otherwise introduces a crafted node name into the Clash configuration. 2. The crafted name contains Python syntax that closes `'''$string'''` and executes an injected statement. 3. The victim invokes `clash-switch.sh auto`, `list`, a region command, or another path that tests proxy latency. 4. `test_proxy_delay` passes the attacker-controlled node name to `urlencode`. 5. `python3 -c` evaluates the generated source and executes the injected Python code with the privileges of the script process. ### Impact Assessment Successful exploitation provides arbitrary local code execution as the user running the script. ...[truncated 311 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Never interpolate untrusted text into executable Python source. Pass the node name as a separate argument: ```bash urlencode() { python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1]))' "$1" } ``` Alternatively, use the already adopted `jq` approach: ```bash printf '%s' "$1" | jq -sRr @uri ``` Additional hardening should include: 1. Treat every proxy and group name returned by Clash as untrusted data. 2. Quote every shell expansion used in command arguments. 3. Add regression tests with quotes, triple quotes, command substitutions, newlines, backslashes, and Unicode node names. 4. Avoid running the script with elevated privileges. 5. Review all dynamically constructed JSON and URL values for equivalent injection defects. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
clash-switch-v2.sh:21
Finding
Predictable Shared Temporary State Enables File Overwrite and Unintended File Reads<![CDATA[ ## Vulnerability Details **File Location**: `clash-switch-v2.sh:21-22`, `clash-switch-v2.sh:54-66`, and `clash-switch-v2.sh:202-205` **Vulnerability Type**: Unsafe temporary file handling and path interpretation **Risk Level**: High ### Vulnerable Code ```bash # 日志和状态文件 LOG_FILE="/var/log/clash-switch.log" STATE_FILE="/tmp/clash-switch-state.json" ``` ```bash # 保存状态 save_state() { local current="$1" local status="$2" echo "{\"timestamp\":\"$(date -Iseconds)\",\"current\":\"$current\",\"status\":\"$status\"}" > "$STATE_FILE" } # 加载状态 load_state() { if [ -f "$STATE_FILE" ]; then cat "$STATE_FILE" else echo "{}" fi } ``` ```bash status) cat $(load_state) ;; ``` ### Technical Analysis The state file uses a fixed name in the globally shared `/tmp` directory. The script performs no ownership, symlink, file-type, or permission validation before redirecting output to that path. A local attacker can pre-create the path as a symbolic link. If a more privileged user later runs `save_state`, shell redirection follows the link and truncates or overwrites the link target. The `status` implementation contains a separate defect: `load_state` prints the contents of the state file, but command substitution passes those contents to `cat` as filenames. Consequently, attacker-controlled whitespace-separated content in the state file can cause the script to read unintended local paths. ### Attack Path **File overwrite path:** 1. A local attacker creates `/tmp/clash-switch-state.json` as a symbolic link to a file writable by the future script process. 2. A privileged user or scheduled task executes the `auto` command. 3. `save_state` redirects JSON output through the symbolic link. 4. The target file is truncated and replaced with state JSON. **File-read path:** 1. A local attacker creates or modifies `/tmp/clash-switch-state.json`. 2. The attacker inserts one or more filesystem paths into its contents. 3. A victim ...[truncated 600 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store state in a private runtime directory such as `${XDG_RUNTIME_DIR}/clash-auto-switch`, not a shared fixed `/tmp` pathname. 2. Create the directory with mode `0700` and state file with mode `0600`. 3. Reject symbolic links and unexpected file ownership before reading or writing. 4. Use an atomic write pattern: create a secure temporary file with `mktemp`, write the state, set permissions, and rename it into place. 5. Correct the status implementation to print the state directly: ```bash status) load_state ;; ``` 6. Build JSON with `jq -n --arg` rather than string interpolation so quotes and control characters in node names cannot corrupt the state document. 7. Do not execute the script with administrative privileges unless a separately justified operation requires them. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
README.md:160
Finding
Scheduled Task Documentation Requests Unnecessary Highest Privileges<![CDATA[ ## Vulnerability Details **File Location**: `README.md:160-165` **Vulnerability Type**: Excessive scheduled-task privileges **Risk Level**: Medium ### Vulnerable Code ```powershell Register-ScheduledTask -TaskName "ClashAutoSwitch" -Trigger (New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 15)) -Action (New-ScheduledTaskAction -Execute "python.exe" -Argument "C:\path\to\clash-switch.py --auto") -RunLevel Highest ``` ### Technical Analysis The documented Windows scheduled task uses `-RunLevel Highest`, although the declared operation only communicates with the Clash controller, performs network health checks, and changes proxy selection. Those functions do not inherently require administrator privileges. The scheduled task is explicitly documented and task-related, so it is not covert persistence or a hidden backdoor. The security defect is the unnecessary privilege level, which violates least privilege and amplifies any compromise of the script, interpreter, dependency, configuration, or executable search path. ### Attack Path 1. A user follows the installation documentation and registers the recurring task with highest privileges. 2. The task repeatedly launches `python.exe` and the project script in an elevated context. 3. An attacker compromises a referenced script, Python dependency, writable configuration, or executable resolution path. 4. The scheduled task executes the attacker-controlled component at its next interval. 5. The payload inherits the elevated task privileges. ### Impact Assessment A successful hijack of any component in the execution chain can obtain the privileges assigned to the scheduled task, potentially including administrator-level access. This can permit system-wide file modification, credential access available to that context, security configuration changes, and installation of additional persistence. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `-RunLevel Highest` from the documented command. 2. Run the task under a dedicated, non-administrative account with only the permissions needed to invoke the local Clash API. 3. Use absolute paths for both `python.exe` and `clash-switch.py`. 4. Place the interpreter and script in directories not writable by untrusted users. 5. Restrict task modification permissions. 6. Document how to remove or disable the task. 7. Keep periodic execution opt-in; do not register it automatically during Skill installation. ]]>

T08 · Insecure Dependencies

Warning
Location
skills/clash-auto-switch/requirements.txt:1
Finding
Unpinned Runtime Dependencies Permit Unaudited Package Resolution<![CDATA[ ## Vulnerability Details **File Location**: `skills/clash-auto-switch/requirements.txt:1`; related installation commands at `README.md:29-31`, `README.md:60-73`, and `docs/openclaw.md:8-11` **Vulnerability Type**: Insecure dependency versioning **Risk Level**: Medium ### Vulnerable Code ```text requests>=2.28.0 ``` The documentation also performs registry-based installation without a pinned package version: ```bash pip install requests ``` ```bash npx clawdhub install clash-auto-switch ``` ### Technical Analysis The Python dependency is constrained only by a minimum version. This permits installation of any future `requests` release accepted by the resolver. The documented `pip install requests` command is likewise unpinned. The `npx` installation command also resolves and executes registry-distributed tooling without a version lock in the documented command. This does not prove that the current upstream packages are malicious. The defect is that the installed code can differ from the audited version over time, weakening reproducibility and expanding exposure to registry compromise, account takeover, or malicious future releases. ### Attack Path 1. A user follows the documentation or installs dependencies from `requirements.txt`. 2. The package resolver queries the configured package registry. 3. A future, compromised, or otherwise unsafe version satisfying the broad constraint is selected. 4. Package installation or import executes code not covered by this project audit. 5. That code receives the permissions and environment of the installing or running user. ### Impact Assessment A compromised dependency can execute arbitrary code as the user performing installation or running the Skill. It may access the `CLASH_SECRET`, OpenClaw configuration, local files, and network resources available to that account. If installation is performed from an administrator or root context, the impact becomes system-wide. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin dependencies to reviewed exact versions. 2. Generate and verify cryptographic hashes, for example with a hash-locked requirements file. 3. Use a lockfile or reproducible build process and update it through reviewed dependency-update pull requests. 4. Pin the package-manager tool used by `npx` and verify the intended publisher and registry source. 5. Install dependencies inside a dedicated virtual environment as a non-privileged user. 6. Add automated vulnerability and provenance scanning for dependency updates. 7. Avoid suggesting unrestricted global or administrator-level package installation. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
skills/clash-auto-switch/clash.py:21
Finding
Clash Bearer Secret Can Be Sent to Arbitrary Plaintext HTTP Endpoints<![CDATA[ ## Vulnerability Details **File Location**: `skills/clash-auto-switch/clash.py:21-40`; equivalent behavior in `clash-switch.py:24-39` **Vulnerability Type**: Sensitive credential transmission over unencrypted transport **Risk Level**: High ### Vulnerable Code ```python def __init__(self, api_url: str = None, secret: str = None, proxy_url: str = None): self.api_url = api_url or os.environ.get("CLASH_API", "http://127.0.0.1:58871") self.secret = secret or os.environ.get("CLASH_SECRET", "") self.proxy_url = proxy_url or os.environ.get("CLASH_PROXY", "http://127.0.0.1:7890") if not self.secret: print("错误: 请设置 CLASH_SECRET 环境变量或提供 --secret 参数") sys.exit(1) self.headers = {"Authorization": f"Bearer {self.secret}"} def _request(self, method: str, endpoint: str, **kwargs) -> Optional[Dict]: """发送 API 请求""" url = f"{self.api_url.rstrip('/')}{endpoint}" try: if method.upper() == "GET": r = requests.get(url, headers=self.headers, timeout=10, **kwargs) elif method.upper() == "PUT": r = requests.put(url, headers=self.headers, timeout=10, **kwargs) ``` ### Technical Analysis Using plaintext HTTP for a controller bound strictly to `127.0.0.1` is a common local-only deployment choice. However, the implementation accepts an arbitrary API URL from command-line arguments or `CLASH_API` and sends the bearer credential to it without validating the scheme or host. If a user configures a non-loopback HTTP controller, the bearer token traverses the network without transport encryption. A network-positioned attacker can observe the authorization header. A maliciously supplied API URL can also deliberately receive the credential. The health-check requests to Telegram, Anthropic, Google, OpenAI, and GitHub do not include this authorization header; the issue is limited to requests made to the configured Clash controller. ### Attack Path 1. The API endpoint is configured ...[truncated 850 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit plaintext HTTP only when the parsed destination is a loopback address such as `127.0.0.1`, `::1`, or a verified local Unix-socket integration. 2. Require HTTPS for non-loopback controller addresses. 3. Keep TLS certificate verification enabled and reject invalid certificates rather than suppressing verification. 4. Validate the URL with a structured URL parser and reject embedded credentials, unexpected schemes, fragments, and malformed hosts. 5. Display a clear error rather than silently sending a secret to a remote plaintext endpoint. 6. Bind the Clash external controller to loopback by default and firewall remote access. 7. Rotate the secret if it has ever been used with a remote HTTP endpoint. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (26)

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The README promotes automatic proxy switching, health checks, and scheduled execution, but does not clearly warn that these operations can change active network routing and affect where user traffic is sent. In a skill context, that omission increases the chance of users enabling unattended behavior that silently alters connectivity, privacy exposure, or service access.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The README instructs users to run `npx clawdhub install clash-auto-switch` without pinning a specific package version. This can cause users to fetch whatever version is current at execution time, increasing supply-chain risk if a malicious or compromised release is published or if behavior changes unexpectedly.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill explicitly supports automated and scheduled execution of `/clash auto`, which can change active proxy/group selections without an explicit warning that network routing will be modified. In an agent or cron context, this can unexpectedly alter connectivity, traffic paths, and service behavior, making the action security-relevant rather than a harmless status check.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The script embeds a hard-coded Clash API bearer token directly in source and then uses it in HTTP requests. Hard-coded secrets are easily exposed through source sharing, backups, logs, shell history, or local file access, allowing unauthorized control of the local proxy manager and potentially traffic redirection or service disruption.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The `switch_to` function modifies the active `ChatGPT` proxy selection through the Clash API, which changes system/application routing behavior. While `auto` suggests automation, the script does not clearly warn in comments or help text that invoking it will actively change proxy configuration and persist state/log files.

External Transmission

Medium
Category
Data Exfiltration
Content
# 切换节点
switch_to() {
    local proxy="$1"
    curl -s -X PUT -H "Authorization: Bearer ${CLASH_SECRET}" \
         -H "Content-Type: application/json" \
         -d "{\"name\":\"$proxy\"}" \
         "${CLASH_API}/proxies/ChatGPT" >/dev/null 2>&1
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
This code presents its description, docstrings, and runtime/user-facing output in Chinese only, including installation guidance and operational messages. That creates a natural-language locale constraint without user opt-in or justification, which matches the language/locale policy violation criteria.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The top-level documentation says the script '优先选择美国/新加坡节点' (prefer U.S./Singapore nodes), but the actual PREFERRED_REGIONS array contains Singapore, Hong Kong, and Japan markers, with no U.S. entries. This is an active contradiction between documented intent and implemented selection logic, not just an omitted detail.

External Transmission

Medium
Category
Data Exfiltration
Content
# Clash API 调用
clash_api_get() {
    local endpoint="$1"
    curl -s -H "Authorization: Bearer ${CLASH_SECRET}" "${CLASH_API}${endpoint}"
}

clash_api_put() {
Confidence
94% confidence
Finding
The script embeds a live Clash controller secret directly in source and uses it in Authorization headers for API calls. Hardcoded secrets are dangerous because anyone with access to the file, logs, backups, or repository can reuse the token to control the local proxy configuration, switch nodes, or inspect controller data; the risk is amplified because the usage output also prints the secret back to the terminal.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The auto_switch flow changes the active proxy configuration automatically when health checks fail, which is a state-changing operation affecting system/network behavior. Although the script logs progress, it does not warn the user in usage/help text or request confirmation before changing the proxy, so the operational impact is not clearly disclosed as a potentially disruptive action.

Rp1

Medium
Category
MCP Rug Pull
Confidence
87% confidence
Finding
The installation command uses `npx clawdhub install clash-auto-switch` without pinning a specific version, which means users may fetch whatever package version is current at install time. This creates a supply-chain risk: a compromised publisher account, malicious update, or unexpected breaking change could be pulled automatically and executed in the user's environment.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The guide instructs users to place `CLASH_SECRET` into a configuration file but does not warn that it is a sensitive credential or advise how to protect it. If that file is committed to source control, shared, logged, or exposed through local compromise, an attacker could use the secret to control the Clash API and alter proxy behavior.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The documentation encourages scheduled automatic execution of `/clash auto`, which changes proxy/network routing state without per-use confirmation or explicit safety notes. In practice this can silently redirect traffic, disrupt expected connectivity, or interfere with security/compliance assumptions about which network path is being used.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill documents automatic proxy switching but does not warn users that changing active proxy groups can disrupt ongoing connections, alter routing, or affect application behavior. In a networking skill, silent configuration changes are security-relevant because they can unexpectedly redirect traffic and interfere with user expectations about connectivity and session stability.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
User-facing strings throughout the file, including installation guidance, error messages, help text, and operational status messages, are written only in Chinese. For a general-purpose skill, this creates a language/locale policy issue because the skill does not provide user opt-in, selection, or justification for restricting interactions to a single language.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
This markdown file contains feature descriptions entirely in Chinese, which can constitute a language/locale policy issue when the skill documentation does not offer a user language choice or explain a required locale. The file does not indicate that the project is region-specific or that Chinese is an intentional, documented constraint.

Natural-Language Policy Violations

Low
Confidence
81% confidence
Finding
The file is named `README.md` and includes an English language toggle link, but nearly all instructional content is written in Chinese. This can be a language/locale policy issue because users are not given an explicit language choice within the file content they open by default.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The documentation instructs users to supply a Clash API secret via command line or environment variables but provides no guidance on secure handling of that credential. This increases the risk of accidental exposure through shell history, logs, process inspection, screenshots, or insecure environment management, especially in shared or automated environments.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
User-facing comments, status messages, and help output are all written in Chinese, with no option to select another language or locale. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy concern.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
The header comment explicitly lists '通知支持 - 切换成功/失败时发送通知' as a new feature. However, the script only logs to a file/stdout and updates a state file; there is no mail, webhook, desktop notification, or other notification mechanism anywhere in the code.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
Comments and configuration define preferred regions as Singapore/Hong Kong/Japan, and later commands expose only US and Singapore regional switching. This imposes locale-specific behavior by default rather than presenting it as a user-selectable policy, which can conflict with language/locale choice expectations.

Intent-Code Divergence

Low
Confidence
79% confidence
Finding
The region_switch function and usage help present U.S./Singapore as supported manual regions, but elsewhere the automatic-selection logic is documented as preferring U.S./Singapore while actually preferring Singapore/Hong Kong/Japan. This creates conflicting intent signals in the file about how regional preference works.

Natural-Language Policy Violations

Low
Confidence
85% confidence
Finding
The natural-language instructions throughout the file are Chinese-only, and there is no indication that the user can choose another language or that the locale constraint is required for a region-specific purpose. Under the stated policy, forcing a specific language without user opt-in is a policy violation.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The documentation instructs users to configure an API secret via command line and environment variables but provides no warning that these values are sensitive and should not be logged, shared, or committed to files. This increases the chance of accidental credential exposure through shell history, screenshots, process listings, or configuration leakage.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.28.0
Confidence
94% confidence
Finding
The dependency is specified as `requests>=2.28.0`, which permits installation of many different future or older-compatible versions rather than a known-good release. This weakens reproducibility and can unintentionally pull in a vulnerable or breaking version during install, especially in automated environments.

Static analysis

No suspicious patterns detected.