T09 · Insecure Skill Coding Practices
- Location
eval-viewer/generate_review.py:286- Finding
Viewer Startup Unconditionally Terminates Processes Using the Selected Port
- Content
View full analysis
Vulnerability Details
File Location:
eval-viewer/generate_review.py, lines 286–306 and 430–432
Vulnerability Type: Uncontrolled termination of an unrelated local process
Risk Level: MediumComplete Code Snippet
python def _kill_port(port: int) -> None: """Kill any process listening on the given port.""" try: result = subprocess.run( ["lsof", "-ti", f":{port}"], capture_output=True, text=True, timeout=5, ) for pid_str in result.stdout.strip().split("\n"): if pid_str.strip(): try: os.kill(int(pid_str.strip()), signal.SIGTERM) except (ProcessLookupError, ValueError): pass if result.stdout.strip(): time.sleep(0.5) except subprocess.TimeoutExpired: pass except FileNotFoundError: print("Note: lsof not found, cannot check if port is in use", file=sys.stderr)The function is invoked unconditionally during viewer startup:
python # Kill any existing process on the target port port = args.port _kill_port(port)Technical Analysis
The evaluation viewer defaults to port 3117 but also accepts a user-selected port through
--port. Before attempting to bind its HTTP server, it invokeslsofto identify every process listening on that port and sends each reported PIDSIGTERM.The code does not establish that the target process is a viewer previously created by this project. It does not verify the executable, command line, process owner, PID file, or viewer-specific instance token. It also does not require explicit confirmation or an opt-in replacement flag.
Consequently, authorization to launch the evaluation viewer is expanded into termination of an arbitrary same-user process outside the viewer's workspace and lifecycle. This is reachable through the documented workflow in
SKILL.md, which instructs the agent to start `eval-viewer/generate_revie ...[truncated 1644 chars]- Remediation
View remediation
Remediation Suggestions
- Remove
_kill_port()from the default startup path. - Attempt to bind the requested port first. If it is unavailable, use the existing fallback that binds to port
0and lets the operating system choose a free port. - If replacing an existing viewer is required, make it explicitly opt-in, such as
--replace-existing-viewer. - Track viewer instances with a securely created PID file containing the PID and a viewer-specific identity token.
- Before terminating a tracked process, verify that:
- the PID still refers to the expected process;
- the process belongs to the current user;
- its executable and command line match this viewer;
- the PID file was not replaced or modified by another user.
- Prefer a graceful viewer-specific shutdown endpoint authenticated with a random local token over sending a generic signal.
- If process termination remains necessary, display the identified process and require explicit confirmation in interactive use.
- Remove
