Back to skill

Security audit

edge-cpu-gguf-tuner

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed offline benchmarking helper that runs only user-supplied local llama.cpp tools, with one resource-control caveat users should understand.

Install only if you want an offline local benchmark helper and are comfortable explicitly choosing the llama-bench binary and GGUF model yourself. Run it as a non-privileged user, keep reports private because they include paths and diagnostics, and avoid untrusted or very noisy benchmark binaries on memory-constrained machines until the output-limiting weakness is fixed.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/edge_cpu_tuner.py:159
Finding
Subprocess Output Limit Is Enforced Only After Unbounded Memory Buffering<![CDATA[ ## Vulnerability Details **File Location**: `scripts/edge_cpu_tuner.py`, lines 159–167 **Vulnerability Type**: Improper resource control leading to local denial of service **Risk Level**: Medium ### Vulnerable Code ```python proc = subprocess.run( list(argv), shell=False, cwd=cwd, env=safe_env(), text=True, encoding="utf-8", errors="replace", stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout_value, check=False, ) output_size = len(proc.stdout.encode("utf-8", "replace")) + len(proc.stderr.encode("utf-8", "replace")) if output_size > max_output_bytes: raise TunerError(f"process output exceeded {max_output_bytes} bytes: {argv[0]}", 1) ``` ### Technical Analysis The process is launched with both `stdout` and `stderr` connected to `subprocess.PIPE`. Python's `subprocess.run()` internally waits for the process and collects its complete output before returning. The configured `max_output_bytes` limit is checked only after `subprocess.run()` has completed and all output has already been buffered in memory. Therefore, the limit constrains only whether the output is accepted after execution; it does not constrain peak memory consumption. A faulty or hostile benchmark executable can continuously emit data until the timeout expires. During that period, Python may retain substantially more than the documented default limit of 8 MiB. Sufficient output can exhaust available memory, invoke the operating system's out-of-memory handling, or destabilize other workloads on a constrained edge host. The timeout limits execution duration but does not provide a reliable memory bound because output can be generated rapidly. Additionally, the implementation does not establish a dedicated process group, so subprocess descendants are not explicitly terminated as a group when a timeout or interruption occurs. ### Attack Path 1. An attacker persuades a user or automation system to run `bench` with a faulty or att ...[truncated 1507 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Replace the fully buffered `subprocess.run()` call with bounded, incremental output collection: 1. Launch the benchmark using `subprocess.Popen`. 2. Read stdout and stderr incrementally without allowing either stream to block the other. Suitable approaches include: - `selectors` with binary, nonblocking pipes on supported platforms; - dedicated reader threads with a shared byte budget; or - temporary files combined with active size monitoring. 3. Track the combined raw byte count before decoding. 4. As soon as the combined output exceeds `max_output_bytes`: - stop reading additional output; - terminate the subprocess; - wait for a short grace period; - forcefully kill it if it does not exit; and - return a controlled output-limit error. 5. Start the subprocess in a dedicated process group or session where supported. On timeout, interruption, or output overflow, terminate the complete group so descendants cannot remain active. 6. Retain only a bounded stderr tail for diagnostics rather than buffering the full stream. 7. Add regression tests using a fake benchmark that: - emits more than the configured byte limit; - emits simultaneously to stdout and stderr; - continues emitting until terminated; and - spawns a child process, to verify process-tree cleanup. 8. Document platform-specific process-group behavior if cross-platform support is required. The output limit must be enforced while bytes are being received, not after the child process has completed. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Self-Modification

High
Category
Rogue Agent
Content
it.

It deliberately does **not** install llama.cpp, download models, call a cloud
API, modify a source tree, edit its own files, or make a universal claim such
as “physical cores always win.”

## What is included
Confidence
90% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Ae1

High
Category
analysis-evasion
Content
3. **No shell execution:** use the entrypoint or `python3 scripts/edge_cpu_tuner.py`; the runner invokes an argument vector with `shell=False`, a reduced enviro
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
3. **No shell execution:** use the entrypoint or `python3 scripts/edge_cpu_tuner.py`; the runner invokes an argument vector with `shell=False`, a reduced enviro
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Env Variable Harvesting

High
Category
Data Exfiltration
Content
def safe_env() -> dict[str, str]:
    env = {k: v for k, v in os.environ.items() if k in SAFE_ENV_KEYS and k not in DANGEROUS_ENV_KEYS}
    env.setdefault("PATH", os.defpath)
    env["LC_ALL"] = "C"
    return env
Confidence
70% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill explicitly describes shell-capable workflows (`sh bin/edge-cpu-tuner ...`) and local file/env interactions, but it does not declare a restrictive tool scope such as `permissions` or `allowed-tools`. Even though the documentation emphasizes offline, no-install, and `shell=False` subprocess use, the missing scope means an integrating agent may grant broader shell/file capabilities than intended, increasing the chance of unintended command execution or file access if the skill is invoked in a permissive runtime.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not math.isfinite(timeout_value) or timeout_value <= 0:
        die("timeout must be a finite positive number")
    try:
        proc = subprocess.run(
            list(argv), shell=False, cwd=cwd, env=safe_env(), text=True,
            encoding="utf-8", errors="replace",
            stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
cmd = [sys.executable, str(HERE / "edge_cpu_tuner.py"), "bench",
               "--binary", str(fake), "--model", str(model), "--threads", "1,2",
               "--repetitions", "3", "--timeout", "10", "--out", str(report), "--json"]
        proc = subprocess.run(cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
        check(proc.returncode == 0, f"fake bench failed: {proc.stdout} {proc.stderr}")
        data = json.loads(proc.stdout)
        check(data["recommendation"]["configuration"]["threads"] == 2, "fake bench winner")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
data = json.loads(proc.stdout)
        check(data["recommendation"]["configuration"]["threads"] == 2, "fake bench winner")
        check(report.exists(), "report persisted")
        rec = subprocess.run([sys.executable, str(HERE / "edge_cpu_tuner.py"), "recommend",
                              "--report", str(report), "--json"], text=True,
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
        check(rec.returncode == 0, "recommend command")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
left, right = root / "left.txt", root / "right.txt"
        left.write_text("same\n")
        right.write_text("same\n")
        gate = subprocess.run([sys.executable, str(HERE / "edge_cpu_tuner.py"), "verify-output",
                               "--baseline", str(left), "--candidate", str(right), "--json"],
                              text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
        check(gate.returncode == 0 and json.loads(gate.stdout)["identical"], "quality gate")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.