Back to skill

Security audit

Ubuntu Browser Session

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its stated browser-session purpose, but needs Review because it can expose an authenticated browser over unauthenticated LAN noVNC and has unsafe persistent state handling.

Install only if you are comfortable giving the agent access to a durable logged-in browser profile. Before use, change noVNC to bind to 127.0.0.1 or require an SSH tunnel, avoid LAN exposure without authentication, use simple trusted session-key values, and stop assisted sessions after login recovery.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/assisted-session.sh:440
Finding
Unauthenticated noVNC service exposes full browser control on all network interfaces## Vulnerability Details **File Location**: `scripts/assisted-session.sh:440-448`, `scripts/assisted-session.sh:498-528`, and `scripts/open-protected-page.sh:350-365` **Vulnerability Type**: Unauthenticated remote browser access over plaintext transport **Risk Level**: Critical ### Vulnerable Code ```bash if ! pid_running "$(read_pid x11vnc)"; then start_process x11vnc "$LOG_DIR/x11vnc.log" \ env DISPLAY="$display" \ x11vnc -display "$display" -forever -shared -rfbport "$VNC_PORT" -localhost -nopw fi if ! pid_running "$(read_pid websockify)"; then start_process websockify "$LOG_DIR/websockify.log" \ websockify --web="$novnc_root" "0.0.0.0:$NOVNC_PORT" "localhost:$VNC_PORT" fi ``` The main wrapper automatically invokes this assisted-access path: ```bash if printf '%s' "$CHALLENGE_JSON" | grep -q '"hasChallenge": *true'; then assisted_helper start --url "$INITIAL_URL" --origin "$ORIGIN" --session-key "$SESSION_KEY" >/dev/null ASSISTED_STATUS="$(assisted_helper status --url "$INITIAL_URL" --origin "$ORIGIN" --session-key "$SESSION_KEY")" emit_result "needs-user" "open-novnc" "$TARGET_ID" "" "$ASSISTED_STATUS" "challenge" "$CDP_PORT" exit 0 fi if printf '%s' "$LOGIN_JSON" | grep -q '"hasLoginWall": *true'; then assisted_helper start --url "$INITIAL_URL" --origin "$ORIGIN" --session-key "$SESSION_KEY" >/dev/null ASSISTED_STATUS="$(assisted_helper status --url "$INITIAL_URL" --origin "$ORIGIN" --session-key "$SESSION_KEY")" emit_result "needs-user" "open-novnc" "$TARGET_ID" "" "$ASSISTED_STATUS" "login-wall" "$CDP_PORT" exit 0 fi ``` ### Technical Analysis `x11vnc` is started with `-nopw`, explicitly disabling VNC authentication. Although the VNC listener itself is restricted to loopback by `-localhost`, `websockify` forwards it through a listener bound to `0.0.0.0`, making the unauthenticated session reachable through every host network interface. The service pr ...[truncated 2384 chars]
Remediation
## Remediation Suggestions 1. Bind websockify to loopback by default: ```bash websockify --web="$novnc_root" "127.0.0.1:$NOVNC_PORT" "127.0.0.1:$VNC_PORT" ``` 2. Require users to access the service through an authenticated SSH tunnel unless LAN publication is explicitly requested. 3. Remove `-nopw`. Use a strong, randomly generated, short-lived VNC credential or an authenticated reverse proxy. 4. If direct network exposure is required, use TLS, a one-time access token, firewall allowlisting, and explicit user confirmation before binding a public interface. 5. Automatically stop `websockify` and `x11vnc` immediately after successful capture, cancellation, or timeout. 6. Add a short maximum assisted-session lifetime and ensure cleanup occurs through signal traps and failure paths. 7. Do not return a LAN URL unless secure LAN publication was explicitly enabled. 8. Add tests asserting that the default listener is `127.0.0.1`, authentication is enabled, and capture terminates the overlay.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/session-manifest.sh:55
Finding
Unvalidated session keys allow path traversal and unintended JSON file overwrite## Vulnerability Details **File Location**: `scripts/runtime-common.sh:31-40`, `scripts/session-manifest.sh:55-58`, and `scripts/session-manifest.sh:136-202` **Vulnerability Type**: Path traversal and arbitrary file overwrite within reachable filesystem paths **Risk Level**: High ### Vulnerable Code Session-scoped paths append the session key without validation: ```bash runtime_scoped_path() { local base_root="$1" local category="$2" local origin="$3" local session_key="${4:-default}" local slug slug="$(origin_slug "$origin")" printf '%s/%s/%s/%s\n' "$base_root" "$category" "$slug" "$session_key" } ``` Manifest paths have the same weakness: ```bash manifest_path() { local origin="$1" local session_key="$2" printf '%s/%s.json\n' "$(origin_dir "$origin")" "$session_key" } ``` The resulting path is opened directly for writing: ```python with open(path, "w", encoding="utf-8") as handle: json.dump(payload, handle, indent=2, sort_keys=True) handle.write("\n") ``` ### Technical Analysis The Skill accepts `--session-key` as an externally supplied string but does not restrict path separators, `..` components, absolute paths, control characters, or excessive length. The value is interpolated directly into runtime directories, profile directories, and manifest filenames. For manifest storage, a value such as `../../index/identity-profiles` produces a path equivalent to: ```text ~/.agent-browser/sessions/<origin>/../../index/identity-profiles.json ``` After filesystem normalization, this escapes the intended origin-specific session directory and targets another JSON file under the browser-state root. Additional traversal may reach other locations writable by the Agent account, subject to the automatically appended `.json` suffix and the existence of parent directories. Runtime and profile path construction is also affected because the session key becom ...[truncated 1733 chars]
Remediation
## Remediation Suggestions 1. Validate every session key before any filesystem operation. A conservative allowlist is recommended: ```bash validate_session_key() { [[ "$1" =~ ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$ ]] || die "invalid session key" } ``` 2. Reject path separators, `..`, absolute paths, empty keys, control characters, and keys exceeding the chosen limit. 3. Resolve the candidate path canonically and verify that it remains beneath the expected root directory before reading, writing, creating directories, or launching Chrome. 4. Use directory file descriptors or equivalent safe-join logic where possible to avoid check-to-use inconsistencies. 5. Reject symlinked destination files and symlinked parent directories. 6. Create files atomically in the trusted destination directory and replace them only after validation. 7. Apply the same validation to site keys, origin-derived keys, profile paths, manifest paths, runtime paths, and log paths. 8. Add regression tests using traversal strings, absolute paths, encoded separators, repeated separators, and symlink destinations.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/assisted-session.sh:106
Finding
Executable shell state files permit command execution when state storage is modified## Vulnerability Details **File Location**: `scripts/assisted-session.sh:106-123` and `scripts/browser-runtime.sh:110-127` **Vulnerability Type**: Shell command injection through sourced persistent state **Risk Level**: High ### Vulnerable Code The assisted-session implementation writes state as shell syntax and later executes it with `source`: ```bash write_state() { mkdir -p "$RUN_DIR" cat >"$STATE_FILE" <<EOF URL=$(printf '%q' "$INITIAL_URL") ORIGIN=$(printf '%q' "$ORIGIN") SESSION_KEY=$(printf '%q' "$SESSION_KEY") RUN_DIR=$(printf '%q' "$RUN_DIR") RUNTIME_RUN_DIR=$(printf '%q' "$RUNTIME_RUN_DIR") MANIFEST_ROOT=$(printf '%q' "$MANIFEST_ROOT") NOVNC_PORT=$(printf '%q' "$NOVNC_PORT") VNC_PORT=$(printf '%q' "$VNC_PORT") PROFILE_DIR=$(printf '%q' "$PROFILE_DIR") LOG_DIR=$(printf '%q' "$LOG_DIR") EOF } load_state() { if [ -f "$STATE_FILE" ]; then # shellcheck disable=SC1090 source "$STATE_FILE" fi } ``` `browser-runtime.sh` uses the same pattern: ```bash load_state() { if [ -f "$STATE_FILE" ]; then # shellcheck disable=SC1090 source "$STATE_FILE" fi } ``` ### Technical Analysis `source` does not parse configuration data; it executes the entire file in the current shell process. The Skill-generated values are escaped with `printf '%q'`, but that protection applies only when the file was created by the trusted writer and remained unchanged. Before sourcing, the implementation does not verify: - File ownership. - File or parent-directory permissions. - Whether the file is a regular file. - Whether the path or any parent component is a symbolic link. - Whether the state resides under a fixed trusted root. - Whether the file contains only expected variable assignments. The scripts also accept `--run-dir`, allowing a caller to select the directory containing `runtime.env` or `assist.env`. If an attacker can create or alter the selected sta ...[truncated 1740 chars]
Remediation
## Remediation Suggestions 1. Replace executable shell state with a non-executable format such as JSON. 2. Parse individual expected fields with a data parser and validate each field's type and allowed range. 3. Keep all state beneath a fixed, canonical, user-owned root rather than accepting arbitrary state directories in production operation. 4. Set `umask 077` before creating runtime, log, manifest, profile-index, and state files. 5. Require state files and parent directories to be owned by the current user and not writable by group or other users. 6. Reject symbolic links and require state files to be regular files. 7. Use atomic creation and replacement with owner-only permissions. 8. If `--run-dir` is retained for testing, gate arbitrary paths behind an explicit test/development mode. 9. Add tests proving that shell metacharacters are treated as data and that unsafe ownership, permissions, and symlinks are rejected.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (43)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description emphasizes browser-session management capabilities: a real Ubuntu browser session, persistent login reuse, manual login recovery, and inspection of protected sites. This code chunk does not implement those behaviors. Instead, it is a narrow content-extraction helper that uses shared CDP evaluation code to run JavaScript on an already-available page and serialize the result. It supports multiple output formats and truncation, but contains no logic for launching a browser, preserving or reusing authentication state, handling manual login workflows, or specifically managing protected sites. While 'host-side page inspection' loosely overlaps with snapshotting, the primary purpose and advertised capabilities are materially broader than what this code actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description describes an operational browser-access capability involving persistent login reuse and protected-site inspection. The supplied code chunk does not implement or invoke any such behavior. It only compiles a Python file and checks its CLI help text, which is a test/validation action. This is a materially different primary purpose from the declared skill behavior, so it should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The declared description suggests a production-facing skill for maintaining a real Ubuntu browser session with persistent logins and possible manual recovery for protected websites. The supplied code does not implement that purpose. It is a test script that creates a local HTML page, starts a browser runtime in headless mode, checks the CDP port, uses snapshot/eval helper scripts to extract links and click one, and then shuts the runtime down. While it does involve a browser runtime and host-side inspection through CDP helpers, the core behavior is narrow automated testing, not durable login/session management or protected-site access. Therefore the description materially overstates and mischaracterizes the code's actual purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The declared purpose is an end-user browser-session capability with durable login reuse and manual login recovery for protected sites. The actual code chunk does not launch or manage a browser session, handle logins, inspect pages, or interact with protected sites. Instead, it is a test harness for runtime-common helper functions and environment/resource allocation logic. While some tested helpers mention noVNC, ports, and X11-related values that could support a browser runtime, this chunk’s primary behavior is internal validation/testing, which is materially different from the declared skill purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description is about operating a real Ubuntu Server browser session and reusing protected-site logins. The supplied code chunk does not launch or interact with a browser, inspect pages, handle protected-site access, or perform login recovery. Instead, it is a test script that exercises a local session-manifest helper by creating temporary files, writing session records, and validating selection/index behavior. That is a materially different primary purpose, so this is a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The declared description emphasizes a live Ubuntu browser session capability with durable login reuse and manual recovery for protected sites. The supplied code chunk does not perform browser automation or site access. Instead, it is a shell test script exercising a local session-registry helper: it writes session records, resolves them, shows default session info, and checks behavior when the registry JSON is corrupted. While this may support durable session reuse infrastructure, the actual code shown is only a persistence/lookup test and lacks the core declared behavior. Therefore the description does not accurately represent this code chunk's primary purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared purpose describes an operational browser automation skill for accessing protected sites via an Ubuntu Server browser session. In contrast, the actual code chunk is only a scope-validation test script. It checks that certain files are absent and that specific documentation text is not present. This is a materially different primary purpose from the declared behavior, and none of the core described capabilities are evidenced in the supplied code. Therefore, the description does not accurately represent what this code chunk actually does.

Ae1

High
Category
analysis-evasion
Content
- `scripts/assisted-session.sh`: bounded manual takeover and capture
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/browser-runtime.sh`: browser runtime, target selection, and page checks
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The evaluate() path forwards arbitrary JavaScript into Runtime.evaluate in the target browser, enabling execution inside whatever page is open, including authenticated sites. In a durable-login browser session, this can read sensitive DOM data, invoke privileged in-page actions, and potentially exfiltrate tokens or private content far beyond the stated purpose of session reuse and inspection.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
fi
    ;;
  stop)
    rm -f "$STATE_DIR/running" "$STATE_DIR/verified"
    ;;
  *)
    echo "unknown command: $command" >&2
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
"$BASE_DIR/assisted-session.sh" capture --run-dir "$TMP_DIR" --manifest-root "$TMP_DIR/github-manifests" --origin "https://github.com" --session-key updated >/dev/null
grep -q '"source_session_key": "updated"' "$TMP_DIR/identity-profiles.json"

rm -f "$TMP_DIR/identity-profiles.json" "$TMP_DIR/runtime/verified"
if PROFILE_STUB_IDENTITY_FILE="$TMP_DIR/identity-profiles.json" \
  RUNTIME_STUB_DIR="$TMP_DIR/runtime" \
  AGENT_BROWSER_RUNTIME_HELPER="$TMP_DIR/runtime-stub.sh" \
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
printf '%s\n' "$github_output" | grep -q '"status": "ready"'
grep -q "$TMP_DIR/home/.agent-browser/profiles/github-oauth-profile" "$TMP_DIR/runtime/profile-dir"

rm -f "$TMP_DIR/home/.agent-browser/index/identity-profiles.json" "$TMP_DIR/runtime/profile-dir" "$TMP_DIR/runtime/mode"
missing_output="$(
  HOME="$TMP_DIR/home" \
  RUNTIME_STUB_DIR="$TMP_DIR/runtime" \
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
printf '%s\n' "$missing_output" | grep -q '"reason": "login-wall"'

printf '{broken json\n' >"$TMP_DIR/home/.agent-browser/index/identity-profiles.json"
rm -f "$TMP_DIR/runtime/profile-dir" "$TMP_DIR/runtime/mode"
corrupt_output="$(
  HOME="$TMP_DIR/home" \
  RUNTIME_STUB_DIR="$TMP_DIR/runtime" \
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
printf '%s\n' "$login_output" | grep -q '"lanNovncUrl": "http://192.168.0.200:6081/vnc.html?autoconnect=1&resize=remote"'
grep -q '^start ' "$TMP_DIR/assisted.log"

rm -f "$TMP_DIR/assisted.log" "$TMP_DIR/runtime-state"
transient_output="$(
  RUNTIME_STUB_MODE="transient-login" \
  RUNTIME_STUB_STATE_FILE="$TMP_DIR/runtime-state" \
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Chaining Abuse

High
Category
Tool Misuse
Content
PORT_A_PID=$!
python3 -m http.server 6080 --bind 127.0.0.1 >/dev/null 2>&1 &
PORT_B_PID=$!
trap 'kill "$PORT_A_PID" "$PORT_B_PID" 2>/dev/null || true; rm -rf "$TMP_DIR"' EXIT

mkdir -p "$TMP_DIR/x11"
touch "$TMP_DIR/x11/X88"
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Chaining Abuse

High
Category
Tool Misuse
Content
PORT_A_PID=$!
python3 -m http.server 6080 --bind 127.0.0.1 >/dev/null 2>&1 &
PORT_B_PID=$!
trap 'kill "$PORT_A_PID" "$PORT_B_PID" 2>/dev/null || true; rm -rf "$TMP_DIR"' EXIT

mkdir -p "$TMP_DIR/x11"
touch "$TMP_DIR/x11/X88"
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill describes and instructs use of shell commands, network access, filesystem state under ~/.agent-browser, and browser/CDP tooling, but it declares no explicit tool scope or permission boundaries. In a skill that handles authenticated browser sessions and persistent login state, missing allowed-tools/permissions increases the risk of overbroad execution, unintended data access, and misuse of powerful host capabilities.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The manual startup sequence publishes a noVNC service on 0.0.0.0:6080 and starts x11vnc with -nopw, which exposes an interactive browser session to the network without authentication. In this skill's context, the browser profile is durable and intended to reuse logged-in sessions, so unauthorized access could let an attacker hijack authenticated web sessions, view sensitive data, or drive the browser as the user.

Session Persistence

Medium
Category
Rogue Agent
Content
```bash
scripts/session-manifest.sh list
scripts/session-manifest.sh show --origin 'https://github.com' --session-key default
scripts/session-manifest.sh write --origin 'https://github.com' --session-key default --state ready --browser-pid 123
scripts/session-manifest.sh mark-stale --origin 'https://github.com' --session-key default --reason 'browser exited'
```
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
## 2. Reuse The Default Site Identity

User intent: agent should use the already logged-in browser context for a site without asking again.

Representative requests:
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Session Persistence

Medium
Category
Rogue Agent
Content
mkdir -p "$RUN_DIR" "$LOG_DIR"
  : >"$logfile"
  setsid "$@" >>"$logfile" 2>&1 &
  local pid=$!
  printf '%s\n' "$pid" >"$(pid_file "$name")"
  sleep 1
Confidence
65% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
mkdir -p "$RUN_DIR" "$LOG_DIR"
  : >"$logfile"
  setsid "$@" >>"$logfile" 2>&1 &
  local pid=$!
  printf '%s\n' "$pid" >"$(pid_file "$name")"
  sleep 1
Confidence
65% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script launches websockify bound to 0.0.0.0, making the noVNC browser session reachable from the network, while x11vnc is configured with -nopw and no additional authentication is added at the noVNC layer. In this skill’s context, the browser is intended to reuse durable authenticated sessions for protected sites, so exposing the session remotely could let another host hijack logged-in web sessions and view or manipulate sensitive pages.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The helper is not limited to passive inspection: it can navigate pages and click links, which are state-changing actions in a logged-in browser context. In this skill’s context of durable session reuse on protected sites, those actions can trigger account operations, consent flows, logout, purchases, or other unintended side effects if exposed to untrusted input.

Static analysis

No suspicious patterns detected.