T09 · Insecure Skill Coding Practices
- Location
check.sh:233- Finding
Full Process Command Lines Are Exposed and Persisted Without Redaction
- Content
View full analysis
Vulnerability Details
File Location:
check.sh, lines 233–258, 260, 384–400, and 404–430
Vulnerability Type: Sensitive information exposure through process enumeration and persistent state storage
Risk Level: MediumVulnerable Code
python ps_out = run(["ps", "axo", "pid=,ppid=,pcpu=,rss=,etime=,comm=,args="]) processes = [] for line in ps_out.strip().split('\n'): parts = line.split(None, 6) if len(parts) < 7: continue pid, ppid, cpu, rss, elapsed, comm, args = parts pid = int(pid) ppid = int(ppid) cpu = float(cpu) rss_kb = int(rss) elapsed_secs = parse_elapsed(elapsed) command = args.strip() first_arg = command.split()[0] if command else "" name = os.path.basename(comm).strip() or os.path.basename(first_arg).strip() or comm.strip() or "unknown" # macOS sometimes truncates comm to 2 chars — fall back to first arg if len(name) <= 2 and first_arg: name = os.path.basename(first_arg).strip() or name processes.append({ "pid": pid, "ppid": ppid, "name": name, "command": command, "cpu_pct": round(cpu, 1), "mem_mb": rss_kb // 1024, "elapsed_secs": elapsed_secs, "elapsed": human_elapsed(elapsed_secs), }) top_processes = sorted(processes, key=lambda p: (p["mem_mb"], p["cpu_pct"]), reverse=True)[:10]The collected command lines are returned in the JSON output:
python result = { "suspicious": len(issues) > 0, "verdict": verdict, "os": platform.system(), "summary": summary, "issues": issues, "top_processes": top_processes, "ignored_normals": ignored, } print(json.dumps(result, indent=2))They are also stored for every enumerated process:
python state = { "timestamp": int(time.time()), "system": { "swap_used_mb": swap_used_mb, ...[truncated 3998 chars]- Remediation
View remediation
Remediation Suggestions
-
Stop requesting or retaining full process arguments. Use
commfor executable identification and collect only PID, PPID, CPU, RSS, and elapsed time.python ps_out = run(["ps", "axo", "pid=,ppid=,pcpu=,rss=,etime=,comm="]) -
Remove the
commandfield fromprocesses,top_processes, anomaly details, and persistent state. Persist only the values required for cross-run comparisons:python "processes": { str(p["pid"]): { "mem_mb": p["mem_mb"], "cpu_pct": p["cpu_pct"], "name": p["name"], } for p in processes } -
If arguments are operationally necessary, make their collection opt-in and redact credential-bearing options, URLs, authorization headers, and environment-like values before output or storage. Prefer an allowlist of explicitly safe arguments over pattern-based removal alone.
-
Create the state directory and file with restrictive permissions. Use directory mode
0700, write through a temporary file opened with mode0600, flush it, and atomically replace the destination. -
Correct permissions on existing installations and delete previously generated state or log files that may contain secrets.
-
Document that monitoring output must not be sent to untrusted logs or consumers, and run the watchdog with the least-privileged account capable of collecting the required metrics.
-
