Back to skill

Security audit

NotebookLM MCP Login

Security checks for vulnerabilities and agentic risk

Overview

The skill’s stated login purpose is coherent, but it handles Google session cookies with an overly exposed browser-debugging setup and incomplete cleanup.

Review before installing. This skill is not shown to exfiltrate data or act deceptively, but it creates and stores reusable Google/NotebookLM session material and leaves too much browser-debugging and temporary-profile exposure. Use only in a trusted local environment, avoid running as root, pin and review dependencies, delete stale /tmp/nlm-chrome-profile data, stop any Chrome process using port 9222 after use, and understand that saved cookies can grant account access until revoked or expired.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (4)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:29
Finding
Unverified Remote Installer Is Piped Directly into a Shell<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 29 **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: Critical ```bash If missing, install Chromium (`apt install chromium-browser`) and uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`). ``` ### Technical Analysis The installation instructions download a mutable shell script from an external URL and immediately execute it through `sh`. There is no version pinning, checksum verification, signature validation, or opportunity to inspect the retrieved content before execution. Although `astral.sh` is associated with the declared `uv` prerequisite and HTTPS protects the connection in transit, the effective payload remains controlled by external infrastructure after this Skill has been reviewed. Compromise of the hosting service, its deployment pipeline, DNS or certificate infrastructure, or an unintended upstream script change could result in arbitrary commands being executed with the invoking user's privileges. This behavior is not required for the Skill's authentication function. A package-manager installation or a separately downloaded and verified installer would provide the prerequisite without creating a direct network-to-shell execution channel. ### Attack Path 1. A user follows the prerequisite installation instructions. 2. The external installer origin or its delivery infrastructure is compromised, or the hosted script changes maliciously. 3. `curl` retrieves the modified response. 4. The shell executes the response immediately without authenticity or integrity validation. 5. The payload performs arbitrary operations under the user's account. ### Impact Assessment A malicious installer would receive the full privileges of the user running the command. It could read or modify user files, steal existing credentials, install persistence, alter executables, download additional payloads, or compromise the NotebookLM authentication data subsequently cr ...[truncated 124 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the `curl | sh` installation instruction. - Prefer installation through a trusted operating-system package manager or another repository with signed metadata. - If an upstream installer is unavoidable: 1. Pin a specific installer or release version. 2. Download it to a local file without executing it. 3. Verify a publisher-provided cryptographic signature or pinned SHA-256 digest. 4. Inspect the verified script before execution. 5. Run it with an unprivileged account and the minimum required permissions. - Document the expected installer digest and provenance in the Skill. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/login.py:27
Finding
Chrome DevTools Is Configured to Accept Arbitrary Origins on a Predictable Port<![CDATA[ ## Vulnerability Details **File Location**: `scripts/login.py`, lines 27–36 **Vulnerability Type**: Overly permissive browser-debugging configuration **Risk Level**: High ```python def launch_chrome(): os.makedirs(TMP_PROFILE, exist_ok=True) proc = subprocess.Popen( [CHROME, f"--remote-debugging-port={PORT}", "--no-first-run", "--no-default-browser-check", "--disable-extensions", f"--user-data-dir={TMP_PROFILE}", "--remote-allow-origins=*"], stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, ) return proc ``` ### Technical Analysis The script launches Chromium with its Chrome DevTools Protocol interface on the fixed port `9222` and sets `--remote-allow-origins=*`. The wildcard relaxes origin restrictions for an interface capable of controlling browser tabs, executing JavaScript, inspecting network activity, and retrieving browser cookies. The browser is specifically used for an interactive Google login, so compromise of the debugging interface during this window can expose valuable authenticated state. The predictable port also makes discovery trivial for untrusted local processes. Depending on the browser version and surrounding network configuration, overly broad origin acceptance may additionally increase exposure to hostile browser-origin or rebinding-based access attempts. Arbitrary-origin access is broader than necessary for the local Python client, which connects directly to `localhost`. ### Attack Path 1. The Skill launches Chromium with remote debugging on port `9222`. 2. The user signs in to a Google account in that browser. 3. An untrusted local process, or another actor able to reach the exposed debugging endpoint, discovers the predictable port. 4. The actor connects to CDP while arbitrary origins are accepted. 5. The actor enumerates targets and uses CDP commands to inspect pages, execute code in browser contexts, or extract authenticated cookies. ### Impact Assessment Su ...[truncated 409 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `--remote-allow-origins=*`. - Explicitly bind the debugging service to the loopback interface where supported. - Select an ephemeral, randomized local port rather than the predictable port `9222`. - Restrict accepted origins to the exact trusted origin needed by the local client, if any origin exception is required. - Keep CDP available only for the minimum duration necessary. - Terminate Chromium immediately after cookie extraction, including on errors, timeouts, and interruptions. - Consider using a browser automation transport based on a private pipe rather than a listening TCP port if supported by the dependency. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/login.py:22
Finding
Authentication-Bearing Chromium Profile and Process Are Not Cleaned Up<![CDATA[ ## Vulnerability Details **File Location**: `scripts/login.py`, lines 22–37 **Vulnerability Type**: Unsafe temporary data and resource lifecycle management **Risk Level**: High ```python CHROME = "/usr/bin/chromium-browser" PORT = 9222 TMP_PROFILE = "/tmp/nlm-chrome-profile" LOGIN_TIMEOUT = 300 # seconds def launch_chrome(): os.makedirs(TMP_PROFILE, exist_ok=True) proc = subprocess.Popen( [CHROME, f"--remote-debugging-port={PORT}", "--no-first-run", "--no-default-browser-check", "--disable-extensions", f"--user-data-dir={TMP_PROFILE}", "--remote-allow-origins=*"], stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, ) return proc ``` The launched process is assigned in `main()` but is never terminated after authentication: ```python def main(): print("Launching Chrome...") proc = launch_chrome() print(f"Chrome PID: {proc.pid}") ``` ### Technical Analysis The browser profile uses a fixed path, `/tmp/nlm-chrome-profile`, which is reused across invocations. Chromium can write cookies, local storage, cache entries, and other authentication-related artifacts to that directory during the Google login. The script does not use a `try/finally` cleanup block, does not terminate or wait for the Chromium process after extraction, and does not remove the temporary profile. Cleanup is also absent from failure, timeout, and interruption paths. Consequently, the debugging interface may remain active after the Skill finishes, and browser state may persist in a location not disclosed by the documented storage section. Use of a predictable path also introduces local filesystem risks, including stale-profile reuse and potential interference by another local user or process, depending on existing path ownership and system permissions. ### Attack Path 1. The script creates or reuses `/tmp/nlm-chrome-profile`. 2. The user authenticates to Google, causing Chromium to store session-related state i ...[truncated 825 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create a unique profile directory using `tempfile.TemporaryDirectory()` rather than a fixed path under `/tmp`. - Ensure the directory is owner-only, such as mode `0700`. - Wrap the entire browser lifecycle in `try/finally`. - In the `finally` block: 1. Request graceful browser termination. 2. Apply a short timeout. 3. Force-kill the process if it does not exit. 4. Call `wait()` to avoid leaving a child process. 5. Remove the temporary profile recursively. - Register cleanup for `KeyboardInterrupt`, authentication timeout, import errors, and cookie-save failures. - Detect and reject pre-existing profile paths instead of silently reusing them. - Document every persistent credential location and apply owner-only permissions to the intended saved profile. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:43
Finding
Unpinned Third-Party Package Is Resolved and Executed at Runtime<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 43 **Vulnerability Type**: Unpinned runtime dependency execution **Risk Level**: Medium ```bash uv tool run --from notebooklm-mcp-cli nlm login --check ``` ### Technical Analysis The verification command identifies `notebooklm-mcp-cli` only by package name and does not specify an audited version or integrity hash. Depending on the local `uv` cache and resolution behavior, this can retrieve and execute package code that differs from the version originally reviewed. The local login script also imports authentication and CDP functions from this dependency. Those imported functions operate directly on sensitive browser cookies and saved profiles. Therefore, a compromised or malicious future package release would execute with the user's privileges and would be positioned to access authentication material. No evidence in the audited files demonstrates dependency confusion or an actually malicious package release. The confirmed issue is the absence of reproducible version and integrity controls around code executed in a sensitive authentication workflow. ### Attack Path 1. An attacker compromises the package publisher account, distribution channel, or a future package release. 2. Dependency resolution selects the malicious version because the instructions do not pin a known-good release. 3. `uv tool run` downloads and executes the package. 4. The package runs with the invoking user's permissions. 5. Malicious package code reads saved profiles, intercepts authentication data, modifies local files, or downloads additional payloads. ### Impact Assessment The dependency executes under the user's account and may access the NotebookLM profile, browser state, environment variables, and other user-readable data. Because the dependency participates in cookie extraction and profile management, compromise could directly expose Google/NotebookLM authentication material. System-wide impact would general ...[truncated 70 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin `notebooklm-mcp-cli` to a specific audited version. - Use a lockfile containing cryptographic hashes for the package and all transitive dependencies. - Configure `uv` to use only the intended trusted package index. - Separate installation from execution so dependency resolution does not occur during the authentication operation. - Review updates before changing the pinned version. - Run the dependency in an isolated environment with only the filesystem and network access required for NotebookLM authentication. - Ensure saved credential files use owner-only permissions and are not exposed to unrelated packages or processes. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill requires shell access and network-capable actions but does not declare any explicit tool scope or permission boundaries. That makes the skill harder to govern safely and increases the chance an agent executes sensitive commands or network operations without clear user-visible authorization, especially in a login workflow handling authentication material.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
This skill extracts Google authentication cookies from a live browser session and saves them locally, but the description does not present that as an explicit upfront warning. Because browser cookies are bearer credentials, inadequate disclosure can mislead users into approving a workflow that grants persistent account access and creates a high-impact credential exposure risk if the files are copied or mishandled.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
The skill invokes an MCP/CLI package by name without pinning a specific version, which creates a supply-chain and reproducibility risk. A future or maliciously substituted package version could change login behavior, exfiltrate cookies, or execute unexpected code during authentication checks.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def launch_chrome():
    os.makedirs(TMP_PROFILE, exist_ok=True)
    proc = subprocess.Popen(
        [CHROME, f"--remote-debugging-port={PORT}",
         "--no-first-run", "--no-default-browser-check",
         "--disable-extensions", f"--user-data-dir={TMP_PROFILE}",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The script extracts Google authentication cookies via Chrome DevTools Protocol and persists them to disk, effectively creating a reusable authenticated session token set. If those cookies or the saved profile are read by another local user, malware, or a later compromised process, an attacker could hijack the user's NotebookLM/Google session without needing credentials or MFA.

External Script Fetching

Low
Category
Supply Chain
Content
which chromium-browser && which uv
```

If missing, install Chromium (`apt install chromium-browser`) and uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`).

### 2. Run the login script
Confidence
93% confidence
Finding
The installation guidance pipes a remotely fetched script directly into sh, which allows arbitrary code execution from the network without verification. If the source is compromised, intercepted, or replaced, a user running the documented command could execute attacker-controlled code on the host.

Natural-Language Policy Violations

Low
Confidence
98% confidence
Finding
The printed login instruction is written only in Chinese, which imposes a specific language on users without opt-in. There is no indication that this script is intended exclusively for Chinese-speaking users or that alternative locales are supported.

Static analysis

No suspicious patterns detected.