Back to skill

Security audit

NotebookLM Studio

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent, but it asks users to rely on an authenticated Google NotebookLM session, optional recurring recovery jobs, and a recovery script with weak path controls.

Review this before installing. Use a dedicated NotebookLM/Google account if possible, treat ~/.notebooklm/storage_state.json like a password, avoid copying it to shared or less-trusted servers, and do not enable the cron recovery jobs unless you need unattended recovery. Prefer pinned dependency versions, do not run the skill or cron as root, and keep output/status files in a private directory.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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 (3)

T08 · Insecure Dependencies

Warning
Location
README.md:93
Finding
Unpinned Third-Party Dependencies and Mutable Update Sources<![CDATA[ ## Vulnerability Details **File Location**: `README.md:93-111` and `README.md:313-316`; equivalent instructions appear in `README.zh-TW.md` **Vulnerability Type**: Supply-chain exposure through unpinned packages and mutable repository branches **Risk Level**: Medium ### Vulnerable Code ```bash npm i -g clawhub # install ClawHub CLI (one-time) clawhub install notebooklm-studio ``` ```bash git clone --recurse-submodules https://github.com/jasontsaicc/notebooklm-studio-skill.git cd notebooklm-studio-skill ``` ```bash pip install "notebooklm-py[browser]" playwright install chromium ``` The documented update procedure also pulls directly from a mutable branch: ```bash cd notebooklm-py && git pull origin main && cd .. pip install -e "notebooklm-py[browser]" ``` ### Technical Analysis The installation instructions do not pin exact npm or Python package versions, package hashes, Git tags, submodule commits, or immutable repository commit IDs. The update procedure explicitly pulls from the mutable `main` branch and installs the resulting checkout in editable mode. The project identifies `notebooklm-py` as an unofficial NotebookLM API and CLI. That CLI operates with an authenticated Google NotebookLM browser session, increasing the sensitivity of any code executed through its installation or update process. No malicious dependency was confirmed during this audit. The vulnerability is that the effective code installed in the future can differ from the code reviewed here. A compromised package publisher, repository account, branch, release pipeline, or transitive dependency could introduce arbitrary installation-time or runtime behavior. ### Attack Path 1. An attacker compromises a dependency publisher, upstream repository, package registry account, or transitive dependency. 2. The attacker publishes a malicious release or modifies the upstream `main` branch. 3. A user follows the documented unpinned installation or update instructions. 4. Packa ...[truncated 1039 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin exact npm and Python dependency versions rather than installing the latest available releases. 2. Provide a lockfile with verified transitive dependency versions and integrity hashes. 3. Pin Git dependencies and submodules to reviewed commit IDs instead of cloning or pulling mutable branches. 4. Replace `git pull origin main` with an update procedure that checks out a signed, reviewed release tag or commit. 5. Publish checksums or signatures for supported releases and document how users should verify them. 6. Recommend installation in a dedicated virtual environment or isolated container under a non-privileged account. 7. Avoid administrator-level package installation unless strictly required. 8. Document the security implications of granting an unofficial CLI access to an authenticated Google session. 9. Add dependency scanning and release-signature verification to the project's publication process. ]]>

T06 · System Persistence

Note
Location
README.md:244
Finding
Optional Cron Jobs Create Durable Authenticated Execution<![CDATA[ ## Vulnerability Details **File Location**: `README.md:244-268`; duplicated in `README.zh-TW.md:244-268` **Vulnerability Type**: Recurring scheduled execution using an authenticated third-party CLI **Risk Level**: Low ### Vulnerable Code ```bash # crontab -e */5 * * * * cd /path/to/notebooklm-studio-skill && bash scripts/recover_tier2_delivery.sh ./output >> /var/log/notebooklm-recovery.log 2>&1 ``` ```bash # crontab -e */30 * * * * notebooklm auth check --test --json | python3 -c "import json,sys; d=json.load(sys.stdin); exit(0 if d['status']=='ok' else 1)" || echo "$(date): AUTH EXPIRED — run notebooklm login" >> /var/log/notebooklm-health.log ``` ### Technical Analysis The documented cron entries survive the Agent run and repeatedly execute commands every five and thirty minutes. The recovery task invokes repository-controlled shell code and the authenticated `notebooklm` CLI. This creates a durable execution channel around code and dependencies that may later change. The persistence is manually configured, clearly documented, and functionally related to recovering long-running NotebookLM artifacts after Agent timeouts. It is therefore not a hidden backdoor. However, scheduled execution is not required for ordinary artifact generation, and it exceeds the minimum privilege and lifetime needed for a single Skill invocation. The examples also rely on the environment's command search path for `bash`, `notebooklm`, and `python3`. Cron environments can have unexpected `PATH` values, and a substituted executable could be invoked if path integrity is not controlled. Writing under `/var/log` may additionally encourage running setup with elevated privileges or loosening log permissions. ### Attack Path 1. A user manually enables the documented recovery and health-check cron jobs. 2. The Skill directory, recovery script, unofficial CLI, or a dependency is subsequently modified or compromised. 3. Cron invokes the modified component automatically withou ...[truncated 955 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Clearly mark both cron jobs as optional and unnecessary for normal Skill operation. 2. Never install scheduled tasks automatically; require informed, explicit user consent. 3. Use a dedicated least-privilege account with access only to the required output directory and NotebookLM state. 4. Use absolute paths for the shell, Python interpreter, NotebookLM CLI, project directory, and scripts. 5. Ensure the Skill directory and scripts are not writable by less-privileged or unrelated users. 6. Store logs in a user-owned directory instead of `/var/log` unless system-managed logging is intentionally configured. 7. Provide exact removal commands and an uninstall procedure for both cron entries. 8. Prefer a temporary per-job scheduler that removes itself after all tracked artifacts reach terminal states. 9. Consider integrity verification of the recovery script before each scheduled invocation. 10. Document credential lifetime and recommend revoking or refreshing the NotebookLM session when recovery is no longer required. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/recover_tier2_delivery.sh:59
Finding
Recovery Status File Allows Unconfined Download Destinations<![CDATA[ ## Vulnerability Details **File Location**: `scripts/recover_tier2_delivery.sh:59-77` and `scripts/recover_tier2_delivery.sh:91-107` **Vulnerability Type**: Untrusted path use from a writable status file **Risk Level**: Medium ### Vulnerable Code The script extracts artifact fields, including `output_path`, directly from `delivery-status.json`: ```bash READ_OUTPUT=$(python3 - "$STATUS_FILE" "$TTL_HOURS" <<'PYEOF' import json, sys from datetime import datetime, timedelta, timezone status_file = sys.argv[1] ttl_hours = int(sys.argv[2]) with open(status_file) as f: data = json.load(f) # TTL check — skip if older than threshold created_at = data.get("created_at", "") if created_at: try: created = datetime.fromisoformat(created_at.replace("Z", "+00:00")) if datetime.now(timezone.utc) - created > timedelta(hours=ttl_hours): sys.exit(0) # stale, skip silently except ValueError: pass # can't parse date, process anyway notebook_id = data.get("notebook_id", "") print(f"NOTEBOOK_ID={notebook_id}") for a in data.get("artifacts", []): if a.get("status") == "pending": print(f"PENDING={a['type']}|{a['task_id']}|{a.get('output_path', '')}") PYEOF ) || continue ``` The values are then consumed without destination validation: ```bash while IFS='|' read -r TYPE TASK_ID OUTPUT_PATH; do [ -z "$TASK_ID" ] && continue echo " Checking $TYPE (task: ${TASK_ID:0:12}...)" # Poll artifact status POLL_RESULT=$(notebooklm artifact poll "$TASK_ID" --json 2>/dev/null || echo '{"status":"unknown"}') STATUS=$(echo "$POLL_RESULT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('status','unknown'))" 2>/dev/null || echo "unknown") case "$STATUS" in completed) echo " ✓ $TYPE completed — downloading" # Download notebooklm download "$TYPE" "$OUTPUT_PATH" -n "$NOTEBOOK_ID" 2>/dev/null && { ``` ### Technical Analysis The `output_path`, artifact `type`, `task_id`, and ` ...[truncated 2603 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat every field in `delivery-status.json` as untrusted input. 2. Resolve the output destination to an absolute canonical path before invoking the CLI. 3. Reject absolute input paths, `..` traversal, symbolic-link escapes, empty destinations, control characters, newlines, and pipe characters. 4. Require the canonical destination to remain beneath the current `SLUG_DIR`. 5. Use fixed server-side filename mappings for each artifact type instead of accepting arbitrary paths from JSON. 6. Allowlist artifact types such as `audio`, `video`, and `slide-deck`. 7. Validate task and notebook IDs against the exact syntax expected by the CLI. 8. Replace the line-oriented pipe-delimited protocol with structured JSON processing. 9. Refuse to overwrite existing files unless overwrite is explicitly expected and safely handled. 10. Create output files using restrictive permissions and verify parent-directory ownership. 11. Protect `delivery-status.json` with restrictive permissions and verify that it is a regular file owned by the recovery account. 12. Do not run the recovery job with elevated privileges. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (25)

Chaining Abuse

High
Category
Tool Misuse
Content
**Ubuntu/Debian:**
```bash
sudo apt update && sudo apt install -y ffmpeg
```

### 4. 認證
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
**Ubuntu/Debian:**
```bash
sudo apt update && sudo apt install -y ffmpeg
```

### 4. 認證
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented purpose understates broader operational behavior such as background polling, recovery workflows, status tracking, and filesystem-based job handoff. These persistence and recovery features make the skill more powerful than a simple one-shot generator and can affect user data retention, unattended execution, and artifact downloads over time.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The documented purpose understates broader operational behavior such as background polling, recovery workflows, status tracking, and filesystem-based job handoff. These persistence and recovery features make the skill more powerful than a simple one-shot generator and can affect user data retention, unattended execution, and artifact downloads over time.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The README instructs users to copy `~/.notebooklm/storage_state.json` from one machine to another to enable headless use, but it does not warn that this file is effectively a persistent authenticated session credential. Anyone who obtains that file may be able to access the user's NotebookLM account/session until it expires or is revoked, so normal file transfer mistakes, backups, logs, or multi-user server exposure become credential-compromise risks.

Session Persistence

Medium
Category
Rogue Agent
Content
notebooklm auth check

# Transfer to server
ssh user@server "mkdir -p ~/.notebooklm"
scp ~/.notebooklm/storage_state.json user@server:~/.notebooklm/storage_state.json
ssh user@server "chmod 600 ~/.notebooklm/storage_state.json"
```
Confidence
94% confidence
Finding
The transfer and server-side placement of `storage_state.json` creates persistent reuse of an authenticated NotebookLM session on another host. In a multi-user or less-trusted server environment, compromise of that host or accidental file exposure can grant account access without needing the original login flow, making the skill context more dangerous because it explicitly operationalizes session portability for automation.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
**Ubuntu/Debian:**
```bash
sudo apt update && sudo apt install -y ffmpeg
```

### 4. 認證
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
**Ubuntu/Debian:**
```bash
sudo apt update && sudo apt install -y ffmpeg
```

### 4. 認證
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The README instructs users to copy `~/.notebooklm/storage_state.json` from a local machine to a server for headless use, but it does not clearly warn that this file contains active authenticated session material equivalent to account access. If the server is less trusted, multi-user, compromised, or logs/transfers are exposed, the copied credential can be stolen and reused to access the user's NotebookLM session.

Session Persistence

Medium
Category
Rogue Agent
Content
notebooklm auth check

# 傳送到伺服器
ssh user@server "mkdir -p ~/.notebooklm"
scp ~/.notebooklm/storage_state.json user@server:~/.notebooklm/storage_state.json
ssh user@server "chmod 600 ~/.notebooklm/storage_state.json"
```
Confidence
93% confidence
Finding
The instructions create a persistent server-side copy of the NotebookLM session state under `~/.notebooklm/storage_state.json`, enabling continued authenticated access from the server. Persisting reusable session material on a remote host increases the attack surface substantially, especially on VPS, CI, or shared systems where host compromise, backup leakage, or local-user access could expose the token.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# 傳送到伺服器
ssh user@server "mkdir -p ~/.notebooklm"
scp ~/.notebooklm/storage_state.json user@server:~/.notebooklm/storage_state.json
ssh user@server "chmod 600 ~/.notebooklm/storage_state.json"
```

### 5. 驗證
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# 傳送到伺服器
ssh user@server "mkdir -p ~/.notebooklm"
scp ~/.notebooklm/storage_state.json user@server:~/.notebooklm/storage_state.json
ssh user@server "chmod 600 ~/.notebooklm/storage_state.json"
```

### 5. 驗證
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
如果 agent 在交付中途超時,`delivery-status.json` 會追蹤待處理的項目。恢復腳本會自動輪詢、下載並更新狀態。

```bash
# crontab -e
*/5 * * * * cd /path/to/notebooklm-studio-skill && bash scripts/recover_tier2_delivery.sh ./output >> /var/log/notebooklm-recovery.log 2>&1
```
Confidence
85% 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
如果 agent 在交付中途超時,`delivery-status.json` 會追蹤待處理的項目。恢復腳本會自動輪詢、下載並更新狀態。

```bash
# crontab -e
*/5 * * * * cd /path/to/notebooklm-studio-skill && bash scripts/recover_tier2_delivery.sh ./output >> /var/log/notebooklm-recovery.log 2>&1
```
Confidence
85% 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
如果 agent 在交付中途超時,`delivery-status.json` 會追蹤待處理的項目。恢復腳本會自動輪詢、下載並更新狀態。

```bash
# crontab -e
*/5 * * * * cd /path/to/notebooklm-studio-skill && bash scripts/recover_tier2_delivery.sh ./output >> /var/log/notebooklm-recovery.log 2>&1
```
Confidence
85% 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
如果 agent 在交付中途超時,`delivery-status.json` 會追蹤待處理的項目。恢復腳本會自動輪詢、下載並更新狀態。

```bash
# crontab -e
*/5 * * * * cd /path/to/notebooklm-studio-skill && bash scripts/recover_tier2_delivery.sh ./output >> /var/log/notebooklm-recovery.log 2>&1
```
Confidence
85% 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.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill writes files and directories locally (`mkdir -p`, temp text files, output artifacts, and `delivery-status.json`) but does not declare any explicit tool scope such as `permissions` or `allowed-tools`. That mismatch weakens policy enforcement and can let the skill perform broader filesystem actions than reviewers or runtime controls expect.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The description says to use the skill whenever the user sends content and asks to generate learning materials, podcasts, videos, or study packages. Those triggers are broad everyday requests and the file does not provide negative examples or tighter scope boundaries, which could cause unintended invocation for generic summarization or media-generation tasks.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The skill applies a default language (`zh_Hant`) to a global NotebookLM account setting, which affects all notebooks in the account rather than only the current task. A user who does not explicitly opt in could have unrelated future work altered, creating cross-task state leakage and unintended account-wide changes.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
Refer to `references/artifact-options.md` for priority levels:
   - **ASK** options: must ask the user
   - **OFFER** options: state the default, let user decide whether to change
   - **SILENT** options: use defaults without asking
   - Options already specified by the user → skip
   - Present all questions in a single message (batch, not one-by-one)
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.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The skill hard-codes `zh_Hant` as the global default language, which can cause the agent to process or generate outputs in a language the user did not request. In this context, that is risky because it can silently alter user-visible output, reduce usability, and create misleading or inaccessible artifacts, especially for users expecting another language.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The file instructs the agent to use the built-in messaging tool to deliver artifacts to Telegram, maintain delivery state, retry sends, and continue until all artifacts reach a terminal status. That behavior materially expands the skill from NotebookLM import/generation into outbound messaging and persistent delivery orchestration, which creates a capability mismatch and can cause unintended exfiltration of generated content to external recipients if the skill is invoked in an unexpected context.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The README says the skill supports 30+ languages but sets a default of Traditional Chinese. That imposes a language default in natural-language behavior without indicating that the user is asked to choose or explicitly opt in, which can violate language/locale policy expectations.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The markdown states `--language` has a default of `en`, which imposes a specific language choice in the skill documentation. Under the policy, forcing a language or locale without user opt-in can be a natural-language policy violation unless clearly justified as region-specific.

Context-Inappropriate Capability

Low
Confidence
76% confidence
Finding
The manifest says the skill imports sources into NotebookLM and generates user-selected artifacts, but this document adds a local media post-processing step via ffmpeg compression. While related to delivery, invoking external post-processing tooling is not part of the stated NotebookLM generation purpose as described.

Static analysis

No suspicious patterns detected.