Back to skill

Security audit

Todolist Md Clawdbot

Security checks for vulnerabilities and agentic risk

Overview

This Drive todo helper is mostly purpose-aligned, but it uses broad Google Drive authority and weak file/credential scoping that users should review before installing.

Review before installing. Use only with a dedicated Google account or isolated Drive folder containing no unrelated files, keep suggestions JSON trusted, prefer dry-run first, and revoke/delete stored OAuth tokens if you stop using it. Do not point it at a broad personal or business Drive until OAuth scope, file opt-in enforcement, and credential handling are tightened.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/todolist_drive_folder_agent.mjs:99
Finding

Managed OAuth requests unrestricted access to the user's entire Google Drive

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/todolist_drive_folder_agent.mjs:424
Finding

Apply mode accepts arbitrary Drive file IDs without validating folder membership or authorization

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/todolist_drive_folder_agent.mjs:337
Finding

Folder runner ignores the documented per-file AI opt-in controls

Content
View full analysis
(f?.mimeType === 'text/markdown') || (f?.name || '').endsWith('.md') ); if (onlyName) mdFiles = mdFiles.filter(f => f.name === onlyName); const changed = []; for (const f of mdFiles) { const fid = f.id; if (!fid) continue; const prev = stFiles[fid] || {}; if (prev.modifiedTime !== f.modifiedTime || prev.size !== f.size) { changed.push(f); } } ``` ```javascript // Build compact LLM request payload for OpenClaw to process. const items = []; for (const f of changed) { const fileId = f.id; const text = await driveDownloadText({ fileId, accessToken }); const openTasks = extractOpenTasks(text, 120); items.push({ fileId, name: f.name, sectionTitle, openTasks, // helpful for applying gate later hint: { modifiedTime: f.modifiedTime, size: f.size, } }); } ``` The documented selection policy states: ```markdown The agent should: - Download `.todolist-md.config.json` when it changes. - Only review files that match include/exclude rules. ``` It also documents marker-based selection: ```markdown The agent should only review files containing that marker. ``` ### Technical Analysis The folder runner selects all files that either advertise a Markdown MIME type or have a `.md` suffix. It does not load `.todolist-md.config.json`, evaluate its include/exclude rules, or require the documented ` true` marker. The optional `onlyName` argument can narrow execution manually, but it does not implement the stated consent mechanism and is not enabled by default. Consequently, every changed Markdown file in the listed folder is treated as eligible for download and task extraction. The genera ...[truncated 1311 chars]
Remediation
View remediation
true` marker before extracting or forwarding task content. 3. Default to deny when neither a valid configuration nor an explicit marker authorizes review. 4. Apply identical authorization checks in prepare and apply modes so an excluded file cannot later be targeted through suggestions. 5. Treat malformed configuration as an error or skip all files rather than silently processing every Markdown file. 6. Record the authorization mechanism and configuration hash in the prepare manifest for later verification. 7. Clearly report skipped and authorized files without including their task content. 8. Add tests covering excluded filenames, disabled AI configuration, absent markers, malformed configuration, and apply attempts against non-opted-in files. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (26)

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 3)May include surrounding context.

md
---
name: todolist-md-clawdbot
description: Operate on todolist-md Markdown todo files. Read + summarize tasks, propose edits, and write outcomes back into Markdown using only <!-- bot: ... --> markers (line-stable write-back).
---

# todolist-md-clawdbot

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 33)May include surrounding context.

md
- Rule: **never insert a new line** once the header exists. Only update the existing header line.
- If the header does not exist, you may insert it at the very top **only if the user explicitly opted into Option B**.
- Canonical format:
  - `<!-- bot: last_review --> 2026-02-04T15:39Z root=<rootFolderId> model=<model>`

6) Never complete tasks without explicit user confirmation.

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · scripts/todolist_drive_folder_agent.mjs (reported line 10)May include surrounding context.

js
* Design goals:
 * - Node-only I/O pipeline (unified)
 * - Minimum tokens: do not call LLM unless a file changed; extract only open tasks
 * - Safe write-back: write ONLY into a dedicated bot section using <!-- bot: ... --> markers
 * - Avoid duplicates: overwrite-update via Drive API files.update(fileId)
 * - Avoid overwriting while you edit: revision gate via headRevisionId
 *

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script reads extra secret material from /root/clawd/.secrets/gog.env and passes account and keyring password values into a subprocess invocation for an unrelated gog tool. In an agent-skill context, this expands the trust boundary far beyond a simple Drive todo updater, enabling access to local secrets and privileged command execution paths that could be abused if the script or environment is compromised.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

The code accesses a local secrets file under /root/clawd/.secrets to retrieve gog account credentials and keyring password, which is unrelated to the core todo-processing task. In an agent environment, harvesting or depending on extra credentials materially increases the blast radius because compromise of this skill can expose credentials for additional systems.

Content

Scanner excerpt · scripts/todolist_drive_folder_agent.mjs (reported line 183)May include surrounding context.

js
const envFile = '/root/clawd/.secrets/gog.env';

  let account = process.env.GOG_ACCOUNT || '';
  let pw = process.env.GOG_KEYRING_PASSWORD || '';

  if ((!account || !pw) && fs.existsSync(envFile)) {
    const text = fs.readFileSync(envFile, 'utf8');

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The script explicitly parses and loads GOG_KEYRING_PASSWORD from a local secret source, expanding access to sensitive credentials not required for its primary function. This creates unnecessary credential exposure and makes the skill more dangerous in a privileged automation context.

Content

Scanner excerpt · scripts/todolist_drive_folder_agent.mjs (reported line 194)May include surrounding context.

js
let v = m[2];
      v = v.replace(/^"|"$/g, '');
      if (k === 'GOG_ACCOUNT' && !account) account = v;
      if (k === 'GOG_KEYRING_PASSWORD' && !pw) pw = v;
      if (k === 'GOG_BIN' && !process.env.GOG_BIN) process.env.GOG_BIN = v;
    }
  }

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

Passing GOG_ACCOUNT and GOG_KEYRING_PASSWORD into a child process environment exposes sensitive credentials to subprocess execution and potentially to process inspection, logs, crash reports, or inherited environments. In a multi-tenant or agent-hosted system, this is a serious secret-handling weakness with unnecessary lateral-risk potential.

Content

Scanner excerpt · scripts/todolist_drive_folder_agent.mjs (reported line 204)May include surrounding context.

js
const cmd = [
    'sudo','-u','ubuntu','-H','env',
    `GOG_ACCOUNT=${account}`,
    `GOG_KEYRING_PASSWORD=${pw}`,
    gogBin,
    'drive','ls','--parent', folderId,'--json'
  ];

Hidden Instructions

High
Category
Prompt Injection
Confidence
70% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · scripts/todolist_drive_folder_agent.mjs (reported line 292)May include surrounding context.

js
`- [ ] Review open tasks in ${fileName} (generated ${now})`,
  ];
  if (openTasks.trim()) {
    lines.push(`  > <!-- bot: note --> Open tasks sampled: ${openTasks.split(/\r?\n/).length}`);
  } else {
    lines.push(`  > <!-- bot: note --> No open tasks found`);
  }

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/todolist_review_drive.py (reported line 49)May include surrounding context.

python
def gog_env() -> Dict[str, str]:
    # Use same pattern as TOOLS.md: run as ubuntu and pass GOG_ACCOUNT/GOG_KEYRING_PASSWORD.
    # Here we just forward current environment; caller should export vars.
    env = os.environ.copy()
    if not env.get("GOG_BIN"):

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/todolist_review_drive.py (reported line 51)May include surrounding context.

python
def gog_env() -> Dict[str, str]:
    # Use same pattern as TOOLS.md: run as ubuntu and pass GOG_ACCOUNT/GOG_KEYRING_PASSWORD.
    # Here we just forward current environment; caller should export vars.
    env = os.environ.copy()
    if not env.get("GOG_BIN"):
        env["GOG_BIN"] = "/home/linuxbrew/.linuxbrew/bin/gog"
    return env

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

The script injects GOG_ACCOUNT and GOG_KEYRING_PASSWORD directly into the command line via env VAR=value arguments to sudo/env. On many systems command-line arguments are observable to other local users through process listing or audit logs, which can disclose the keyring password and compromise the authenticated Drive account.

Content

Scanner excerpt · scripts/todolist_review_drive.py (reported line 67)May include surrounding context.

python
"-H",
        "env",
        f"GOG_ACCOUNT={env.get('GOG_ACCOUNT','')}",
        f"GOG_KEYRING_PASSWORD={env.get('GOG_KEYRING_PASSWORD','')}",
        gog,
        "drive",
        "ls",

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

This repeats the same credential exposure pattern for the download path: the keyring password is embedded in process arguments when invoking sudo/env/gog. In the context of a Drive-review automation skill, that is more dangerous because the script operates on potentially sensitive documents and the exposed credential may grant broader Drive access than a single file.

Content

Scanner excerpt · scripts/todolist_review_drive.py (reported line 91)May include surrounding context.

python
"-H",
        "env",
        f"GOG_ACCOUNT={env.get('GOG_ACCOUNT','')}",
        f"GOG_KEYRING_PASSWORD={env.get('GOG_KEYRING_PASSWORD','')}",
        gog,
        "drive",
        "download",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill explicitly instructs the agent to persist storage configuration such as local paths, Drive folder IDs, S3 bucket/prefix information, and stable identity keys for future runs. While this is operationally useful, these values can reveal sensitive filesystem layout, cloud resource identifiers, and repository locations if stored insecurely or without user awareness, creating avoidable privacy and targeting risk.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation states 'write ONLY into a dedicated bot section', implying modifications are confined to an existing marked section. However, ensureBotSuggestedSection creates a new titled section and bot marker block when the section is absent, which modifies document structure beyond merely updating an existing dedicated section.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The header says the script 'does NOT call any LLM', which is literally true, but the surrounding documentation presents the script as limited to a non-LLM role while the implementation materially participates in an LLM workflow by creating request JSON in prepare mode and writing LLM suggestions into Drive in apply mode. That documentation understates the script's effective behavior and intent.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/todolist_agent_entrypoint.mjs (reported line 57)May include surrounding context.

js
}

async function oauthAccessTokenFromRefresh({ refreshToken, clientId, clientSecret }) {
  const res = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/todolist_agent_entrypoint.mjs (reported line 85)May include surrounding context.

js
}

async function oauthAccessTokenFromRefresh({ refreshToken, clientId, clientSecret }) {
  const res = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/todolist_drive_folder_agent.mjs (reported line 54)May include surrounding context.

js
}

async function oauthAccessTokenFromRefresh({ refreshToken, clientId, clientSecret }) {
  const res = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/todolist_drive_folder_agent.mjs (reported line 82)May include surrounding context.

js
}

async function oauthAccessTokenFromRefresh({ refreshToken, clientId, clientSecret }) {
  const res = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The top-level documentation says the script 'only' performs Drive listing, state comparison, and optional header updating. However, the implementation explicitly downloads changed files to /tmp before modifying them, which is a material side effect not reflected in that enumerated behavior.

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/todolist_review_drive.py (reported line 44)May include surrounding context.

python
def sh(cmd: List[str], env: Dict[str, str] | None = None) -> str:
    out = subprocess.check_output(cmd, env=env, text=True)
    return out

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code passes GOG_ACCOUNT and GOG_KEYRING_PASSWORD into sudo ... env when listing and downloading Drive files, which involves handling sensitive credentials and making networked access to Google Drive. Although the module docstring mentions that gog must already be authenticated, there is no user-facing warning, confirmation, or logging near these credential-using operations explaining that credential environment variables are consumed for remote access.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The comment 'Optionally stamp header on changed files' implies the files themselves are updated. In practice, the script downloads the file, edits a local /tmp copy, and prints that agent upload is still needed; no remote Drive update occurs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script downloads remote Drive content to a predictable path under /tmp using the Drive file ID as the filename, without warning users or using secure temporary-file creation. On multi-user systems this can expose sensitive document contents, enable symlink clobbering attacks, or leave recoverable remnants of downloaded files in a shared temporary directory.

Content

No source excerpt is available for this finding.

Tainted flow: 'new' from pathlib.Path.read_text (line 187, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

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

python
else:
                # NOTE: actual upload/in-place update should be implemented by the agent using Drive API files.update.
                # We intentionally do not embed secrets/token logic here.
                tmp.write_text(new, encoding="utf-8")
                print(f"[needs-agent-upload] updated local copy for {f.get('name')} ({fid})")

    state["lastScanAtUtc"] = iso_utc_now()

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access, suspicious.exposed_secret_literal (+1 more)

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/todolist_drive_folder_agent.mjs:208

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/todolist_agent_entrypoint.mjs:192

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/todolist_drive_folder_agent.mjs:179

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/todolist_agent_entrypoint.mjs:198

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/todolist_drive_folder_agent.mjs:315

Sensitive-looking file read is paired with a network send.

Warn
Code
suspicious.potential_exfiltration
Location
scripts/todolist_agent_entrypoint.mjs:157

Sensitive-looking file read is paired with a network send.

Warn
Code
suspicious.potential_exfiltration
Location
scripts/todolist_drive_folder_agent.mjs:100