Back to skill

Security audit

Brower Opener

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it says, but it defaults to exposing authenticated Chrome sessions for automation and can abruptly close unrelated browser or port processes.

Install only if you are comfortable with an agent-controlled Chrome debugging port and cookie reuse. Prefer independent mode, avoid personal or production browser profiles, close the debug browser after use, and be aware that reuse mode may close Chrome windows and leave a copied profile on disk.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/launcher.py:276
Finding

Authenticated Browser Profile Is Persistently Copied and Exposed Through Chrome DevTools

Content
View full analysis

Vulnerability Details

File Location: scripts/launcher.py:276-316; related behavior in scripts/start_chrome_close.sh:98-103 and documented as the default workflow in SKILL.md:31-39,69-80,226-229
Vulnerability Type: Exposure of authenticated browser state through an unauthenticated local debugging interface
Risk Level: High

Vulnerable Code

scripts/launcher.py:276-316:

python
reuse_profile = os.path.expanduser("~/.chrome-reuse-profile")

if default_profile and os.path.isdir(default_profile):
    print(f"[INFO] Copying default profile to {reuse_profile}...")
    try:
        import shutil

        def _ignore_runtime_files(src, names):
            return {
                name for name in names
                if name in {
                    "SingletonLock",
                    "SingletonCookie",
                    "SingletonSocket",
                    "RunningChromeVersion",
                }
            }

        if os.path.exists(reuse_profile):
            shutil.rmtree(reuse_profile)
        shutil.copytree(
            default_profile,
            reuse_profile,
            ignore=_ignore_runtime_files,
        )
        print("[INFO] Profile copied successfully")
    except Exception as e:
        print(f"[WARNING] Failed to copy default profile: {e}")
        print("[WARNING] Falling back to independent profile")
        reuse_profile = os.path.expanduser("~/.chrome-debug-profile")
else:
    print("[WARNING] Default profile not found, using independent profile")
    reuse_profile = os.path.expanduser("~/.chrome-debug-profile")

cmd = [
    chrome_path,
    "--remote-debugging-port=9222",
    f"--user-data-dir={reuse_profile}",
    "--no-first-run",
    "--no-default-browser-check"
]

scripts/start_chrome_close.sh:98-103:

bash
nohup "$CHROME_PATH" \
    --remote-debugging-port=9222 \
    --no-first-run \
    --no-d
...[truncated 2696 chars]
Remediation
View remediation

Remediation Suggestions

  1. Make independent-profile mode the default and require explicit, informed user consent before reusing authenticated state.
  2. Do not launch remote debugging against the live default browser profile.
  3. If profile reuse is essential, copy only the minimum required state into a securely created temporary directory rather than a persistent directory under the user's home folder.
  4. Set restrictive directory permissions so only the current user can access the temporary profile.
  5. Remove the temporary profile in a reliable cleanup routine after Chrome exits, including cleanup after startup failures.
  6. Explicitly bind remote debugging to loopback using the supported Chrome debugging-address option.
  7. Prefer a dynamically selected random port instead of the predictable fixed port 9222.
  8. Track the launched browser process and disable the debugging endpoint as soon as automation completes.
  9. Warn the user that reuse mode exposes authenticated browser capabilities to local CDP clients.
  10. Remove or deprecate start_chrome_close.sh unless it is changed to use a controlled temporary profile.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/launcher.py:108
Finding

Unverified and Overbroad Process Termination Can Kill Unrelated Applications

Content
View full analysis

Vulnerability Details

File Location: scripts/launcher.py:108-128,230-250; related behavior in scripts/start_chrome.sh:31-50 and scripts/start_chrome_close.sh:19-38
Vulnerability Type: Destructive process management without ownership or identity validation
Risk Level: Medium

Vulnerable Code

scripts/launcher.py:108-128:

python
if system == "windows":
    try:
        # Find the process occupying the port
        result = subprocess.run(
            ["netstat", "-ano"],
            capture_output=True,
            text=True,
            timeout=5
        )

        for line in result.stdout.split('\n'):
            if f":{port}" in line and "LISTENING" in line:
                parts = line.split()
                if len(parts) >= 5:
                    pid = parts[-1]
                    try:
                        subprocess.run(
                            ["taskkill", "/F", "/PID", pid],
                            capture_output=True,
                            timeout=5
                        )
                    except:
                        pass
    except:
        pass

scripts/launcher.py:230-250:

python
# Close all Chrome processes
print("[WARNING] Closing all Chrome processes...")
if system == "windows":
    try:
        subprocess.run(
            ["taskkill", "/F", "/IM", "chrome.exe"],
            capture_output=True,
            timeout=10
        )
    except:
        pass
else:
    try:
        subprocess.run(
            ["pkill", "-9", "-f", "Google Chrome"],
            capture_output=True,
            timeout=10
        )
    except:
        pass

scripts/start_chrome.sh:33-50:

bash
if command -v lsof >/dev/null 2>&1; then
    if lsof -Pi :9222 -sTCP:LISTEN -t >/dev/null 2>&1; then
        for pid in $(lsof -Pi :9222 -sTCP:LISTEN -t); do
            echo "[INFO] Found 
...[truncated 3584 chars]
Remediation
View remediation

Remediation Suggestions

  1. Do not automatically kill an arbitrary process when port 9222 is occupied. Abort startup and report the conflict instead.
  2. Select an available dynamic port when the preferred port is unavailable.
  3. Record the PID and executable identity of every Chrome process launched by the Skill.
  4. Only terminate a process if its PID, owner, executable path, and launch token match a process previously created by this Skill.
  5. Replace broad pkill -f patterns with direct signaling of a verified PID.
  6. Attempt graceful browser shutdown first and allow sufficient time for profile data to be flushed.
  7. Reserve forced termination for an explicit user-approved recovery action.
  8. Display a clear confirmation prompt before closing existing browser windows.
  9. Check command return values and report failures instead of suppressing all exceptions.
  10. Apply the same process-verification logic consistently across the Python and shell launchers.

T07 · Tool Hijacking and Spoofing

Note
Location
scripts/health.py:46
Finding

Health Check Accepts Arbitrary or Malformed Services on Port 9222 as Healthy Chrome

Content
View full analysis

Vulnerability Details

File Location: scripts/health.py:46-77
Vulnerability Type: Fail-open service identity validation
Risk Level: Low

Vulnerable Code

python
def check_chrome_version():
    """
    Check Chrome version using socket HTTP request.
    Avoids urllib to prevent browser auto-opening.
    """
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(3)
        sock.connect(('127.0.0.1', 9222))

        # Send HTTP GET request manually
        request = b"GET /json/version HTTP/1.1\r\nHost: 127.0.0.1:9222\r\n\r\n"
        sock.sendall(request)

        # Receive response
        response = b""
        while True:
            try:
                chunk = sock.recv(4096)
                if not chunk:
                    break
                response += chunk
                if b"\r\n\r\n" in response:
                    break
            except socket.timeout:
                break

        sock.close()

        # Check if response contains Chrome info
        response_str = response.decode('utf-8', errors='ignore')
        if 'Browser' in response_str or 'WebKit' in response_str or 'protocolVersion' in response_str:
            return True, "Chrome is healthy and responding on port 9222"

        return True, "Port 9222 is open (Chrome may be starting)"
    except Exception as e:
        return True, "Port 9222 is open (response check failed)"

Technical Analysis

The health check correctly attempts to request /json/version, but it fails open. If the returned data does not contain any expected Chrome markers, the function still returns True. If connection handling, decoding, or response processing raises an exception after the initial port check, the exception handler also returns True.

The response is not parsed as HTTP or JSON. It does not validate the HTTP status code, required CDP fields ...[truncated 1412 chars]

Remediation
View remediation

Remediation Suggestions

  1. Return failure for malformed responses, missing expected fields, socket exceptions, and timeouts.
  2. Parse the HTTP status line and require a successful status code.
  3. Read the complete response body according to Content-Length or valid HTTP framing.
  4. Parse the body as JSON and require expected CDP properties such as Browser, Protocol-Version, and webSocketDebuggerUrl.
  5. Validate that webSocketDebuggerUrl uses a loopback host and the expected port.
  6. Optionally connect to the reported WebSocket endpoint and perform a harmless CDP version request to verify protocol behavior.
  7. Do not treat an open TCP port as proof that Chrome is starting.
  8. Ensure sockets are closed through a context manager or finally block.
  9. Log the actual validation error while avoiding disclosure of sensitive browser metadata.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (33)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The README explicitly promotes launching Chrome with the user's main profile and reusing existing cookies/session state for automated testing, but it provides no warning that this exposes authenticated sessions, personal browsing data, and persistent credentials to the automation environment. In this skill context, that is especially dangerous because the whole purpose is to let another component attach via CDP and operate inside the already-authenticated browser, which can lead to account takeover, data exfiltration, or unintended actions if the tooling or generated tests are compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The README instructs users to expose Chrome's remote debugging interface on port 9222 and have Playwright connect to it, but it omits any warning that CDP access effectively grants powerful control over the browser, including page interaction, script execution, cookie inspection, and access to authenticated sessions. This becomes more dangerous here because the same document also encourages reusing the main browser profile, so an attacker or untrusted local process that reaches the port could hijack a live privileged session.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Force-closing all Chrome windows and killing any process bound to port 9222 goes beyond a normal browser opener and can disrupt unrelated applications or destroy active user work. Combined with reuse of the main browser profile, this also exposes authenticated browsing context via remote debugging, which raises the risk of local session compromise if another component connects to DevTools.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Force-closing all Chrome windows and killing any process bound to port 9222 goes beyond a normal browser opener and can disrupt unrelated applications or destroy active user work. Combined with reuse of the main browser profile, this also exposes authenticated browsing context via remote debugging, which raises the risk of local session compromise if another component connects to DevTools.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

Force-closing all Chrome windows and killing any process bound to port 9222 goes beyond a normal browser opener and can disrupt unrelated applications or destroy active user work. Combined with reuse of the main browser profile, this also exposes authenticated browsing context via remote debugging, which raises the risk of local session compromise if another component connects to DevTools.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The launcher forcibly kills all Chrome processes without user confirmation before starting reuse mode. In this skill's context, that is especially dangerous because it targets the user's real browser state and can destroy active work, interrupt authenticated sessions, and risk profile corruption while handling sensitive cookies/session data.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares shell, network, and file-capable behavior but does not constrain those capabilities with explicit tool scope. In practice, this allows a browser-launch skill to terminate processes, open debug ports, and manipulate local state without clear authorization boundaries, increasing the chance of unintended or unsafe execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The description does not prominently warn that the skill may close existing Chrome windows, kill processes on a port, and reuse the main browser profile by default. Because these actions affect user data, running applications, and authenticated sessions, insufficient upfront warning materially increases the likelihood of accidental harmful use.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Overly broad trigger phrases like generic requests to 'open browser' can activate a high-impact skill in routine conversations without the user understanding that it may reuse cookies, expose a debug port, or close running browser windows. This is dangerous because the trigger does not match the sensitivity of the resulting actions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Defaulting all unspecified cases to cookie-reuse mode makes the most privacy-sensitive and disruptive behavior the fallback path. In context, this is more dangerous because the skill is designed to expose Chrome through a remote debugging port, so reusing the primary profile can grant access to logged-in sessions without a clear affirmative choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The module docstring and CLI help text are written in Chinese only, which imposes a specific language/locale on users without any opt-in or explanation that the tool is region-specific. The policy requires avoiding language/locale constraints unless the user is given a choice or the constraint is clearly justified.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The documentation claims independent mode is 'incognito', but the implementation actually uses a persistent user-data directory on disk. This can mislead users into believing browsing artifacts, cookies, and session data will not persist, causing unintentional retention of sensitive data in a tool specifically marketed for cookie/session reuse.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/launcher.py (reported line 50)May include surrounding context.

python
# 尝试使用 where 命令
    try:
        result = subprocess.run(
            ["where", "chrome.exe"],
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/launcher.py (reported line 89)May include surrounding context.

python
# 尝试使用 which 命令
    for cmd in ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]:
        try:
            result = subprocess.run(
                ["which", cmd],
                capture_output=True,
                text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/launcher.py (reported line 110)May include surrounding context.

python
if system == "windows":
        try:
            # 查找占用端口的进程
            result = subprocess.run(
                ["netstat", "-ano"],
                capture_output=True,
                text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
88% confidence
Finding

Although the subprocess call itself is fixed-form, the logic kills any PID associated with the target port without validating ownership or origin. That can terminate unrelated local applications using port 9222, creating a denial-of-service condition against user processes and potentially disrupting legitimate development workflows.

Content

Scanner excerpt · scripts/launcher.py (reported line 123)May include surrounding context.

python
if len(parts) >= 5:
                        pid = parts[-1]
                        try:
                            subprocess.run(
                                ["taskkill", "/F", "/PID", pid],
                                capture_output=True,
                                timeout=5

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/launcher.py (reported line 135)May include surrounding context.

python
else:
        # macOS/Linux
        try:
            subprocess.run(
                ["lsof", "-ti", f":{port}"],
                capture_output=True,
                timeout=5

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
78% confidence
Finding

This code performs a safety-relevant subprocess operation intended to identify and handle the process using port 9222, but there is no print/log, confirmation, or explanatory comment warning the user that another process may be affected on macOS/Linux. For code files, safety-critical process-management behavior should have some visible disclosure when it can impact other running applications or sessions.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/launcher.py (reported line 195)May include surrounding context.

python
# 启动 Chrome(非阻塞)
    try:
        if system == "windows":
            subprocess.Popen(
                cmd,
                creationflags=creation_flags,
                stdout=subprocess.DEVNULL,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/launcher.py (reported line 203)May include surrounding context.

python
start_new_session=True
            )
        else:
            subprocess.Popen(
                cmd,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/launcher.py (reported line 332)May include surrounding context.

python
start_new_session=True
            )
        else:
            subprocess.Popen(
                cmd,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
94% confidence
Finding

This code forcibly terminates all Chrome processes on Windows without confirming with the user or limiting termination to a process started by this tool. In a browser-launching skill that advertises cookie/session reuse, this can cause loss of user work, interruption of unrelated browsing sessions, and abrupt shutdown of active authenticated contexts.

Content

Scanner excerpt · scripts/launcher.py (reported line 236)May include surrounding context.

python
print("[WARNING] Closing all Chrome processes...")
    if system == "windows":
        try:
            subprocess.run(
                ["taskkill", "/F", "/IM", "chrome.exe"],
                capture_output=True,
                timeout=10

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

This Unix branch uses 'pkill -9 -f "Google Chrome"' to indiscriminately kill matching Chrome processes, which is destructive and broader than necessary. In context, the skill is explicitly intended to reuse active browser state, so unexpectedly forcing shutdown of all Chrome windows can disrupt sessions and cause data loss or corruption in profile state.

Content

Scanner excerpt · scripts/launcher.py (reported line 245)May include surrounding context.

python
pass
    else:
        try:
            subprocess.run(
                ["pkill", "-9", "-f", "Google Chrome"],
                capture_output=True,
                timeout=10

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code recursively deletes and recopies a Chrome profile directory containing potentially sensitive cookies, tokens, history, and local storage into a predictable location without strong disclosure or safeguards. In a skill designed for session reuse, silent replication of this data materially increases exposure of authentication material and privacy-sensitive local artifacts.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/launcher.py (reported line 324)May include surrounding context.

python
# 启动 Chrome(非阻塞)
    try:
        if system == "windows":
            subprocess.Popen(
                cmd,
                creationflags=subprocess.CREATE_NEW_PROCESS_GROUP,
                stdout=subprocess.DEVNULL,

Static analysis

No suspicious patterns detected.