Back to skill

Security audit

google-photos-takeout-pipeline

Security checks for vulnerabilities and agentic risk

Overview

This backup skill is purpose-built, but it needs review because it handles live Google session cookies and stores or uses them with broader access than its safety wording suggests.

Install only if you are comfortable granting a local agent access to a logged-in Google browser session. Use a dedicated Chromium profile for Takeout, avoid the --linux-browser-cmd option unless you fully control the value, store cookie jars and URL files only in private locations, delete them immediately after the run, and review the scripts before using them on an account that contains sensitive data.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/takeout_download.py:70
Finding

Excessive Collection of Google and YouTube Session Cookies

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/takeout_download.py:83
Finding

Predictable Temporary Cookie Jar Persists After Execution

Content
View full analysis
0 else 2147483647 f.write(f"{dom}\t{flag}\t{c.get('path', '/')}\t" f"{'TRUE' if c.get('secure') else 'FALSE'}\t{exp}\t{c['name']}\t{c['value']}\n") ``` ```python ap.add_argument("--jar", default="/tmp/takeout_cookies_all.netscape") ``` ### Technical Analysis The default cookie jar is stored at a fixed, predictable path under `/tmp`. The file contains plaintext session cookies. Mode `0600` limits ordinary reads to the owner, but it does not address all temporary-file risks. The file is opened with `O_CREAT | O_TRUNC` without exclusive creation or no-follow protection. The code does not verify that an existing path is a regular file owned by the current user. It also never removes the jar on normal completion, exceptions, interruption, or download failure. Consequently, reusable authenti ...[truncated 1100 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/takeout_download.py:46
Finding

Arbitrary Shell Command Execution Through Linux Browser Command

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
README.md:41
Finding

Unpinned Third-Party Dependency Installation

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/discover_url.py:62
Finding

Sensitive Takeout URL Written and Printed Without Protection

Content
View full analysis
{args.out}", file=sys.stderr) ``` ### Technical Analysis The discovered URL includes Takeout job and user identifiers and is described by the project as session-bound. The script prints the complete URL to standard output and optionally writes it using the process's default umask. The output file is not explicitly restricted to mode `0600`, and the code does not protect against an existing symlink or validate the destination type. Standard output may also be retained by terminal logs, Agent transcripts, CI logs, shell redirection, or process supervisors. While cookies may still be required to use the URL, exposing the complete URL discloses sensitive account and export metadata and may contribute to archive access when combined with other session material. ### Attack Path 1. The user runs `discover_url.py`, optionally through an Agent or logged terminal. 2. The script prints the complete Takeout URL to standard output. 3. The output is captured in a transcript, command log, redirected file, or monitoring system. 4. Alternatively, `--out` writes the URL to a file with permissions determined by the user's umask. 5. Another user, process, or log consumer obtains the URL. 6. The recipient attempts to access the export while the URL is valid, potentially combining it with separately obtained browser cookies. ### Impact Assessment Exposure reveals Takeout job identifiers, user identifiers, timestamped archive names, and the final download endpoint. If the URL is usable with available session material, it can assist unauthorized retrieval of the user's exported data. This issue does not independently g ...[truncated 121 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documented behavior claims a much broader automation pipeline than the detected implementation apparently provides. This mismatch is security-relevant because users may approve the skill based on incomplete or inaccurate expectations, undermining informed consent for sensitive operations involving cookies, downloads, and filesystem changes.

Content

No source excerpt is available for this finding.

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Confidence
94% confidence
Finding

Harvesting session cookies from a running browser via CDP matches information-stealer behavior because those cookies can impersonate the logged-in Google account without a password. In this skill's context, the behavior is presented as functional rather than overtly malicious, but it remains highly sensitive and dangerous because stolen or mishandled session cookies can enable account access and bulk data exfiltration.

Content

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

md
only fallback phases, the chrome://downloads shadow-DOM control snippets, and
the Google→iCloud direct-transfer flow with its three manual user steps).

## Security model (read before installing)

This skill handles **session cookies of a logged-in Google account**. That is inherent
to Takeout automation (Takeout itself is cookie-gated). The scripts are built to touch
the minimum:

- **Reads:** cookies via the local Chrome DevTools Protocol (localhost:9222) of YOUR
  browser, filtered to `*.google.com` / `*.googleusercontent.com` domains only —
  cookies of banks, shops and other services never leave the browser.
- **Writes:** a Netscape cookie jar (chmod 600) in `/tmp` (or `--jar` path), used only
  to talk to `takeout-download.usercontent.google.com` (i.e. Google). Delete it after
  the run — it is not needed for anything else.
- **Network:** only Google hosts are contacted. No telemetry, no third-party calls.
- **No login automation.** The scripts never type passwords, never c

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
100% confidence
Finding

This is a true tool-parameter-abuse issue: the --linux-browser-cmd option allows arbitrary shell command execution because it is fed directly into subprocess.run(..., shell=True). In the context of a pipeline designed to extract authenticated Google cookies from a live browser, successful exploitation can lead to full compromise of the host session, credential theft, and execution of follow-on malicious actions.

Content

Scanner excerpt · scripts/takeout_download.py (reported line 57)May include surrounding context.

python
"--remote-debugging-port=9222",
                        "--no-first-run", "--no-default-browser-check"])
    else:
        subprocess.run(linux_cmd or "chromium --remote-debugging-port=9222 --no-first-run",
                       shell=True)
    for _ in range(10):
        time.sleep(3)

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The README presents a reassuring security model that says cookies are filtered to *.google.com only, but earlier text explicitly states the workflow uses CDP Storage.getCookies to harvest the full browser cookie jar because filtered retrieval 'silently fails.' That discrepancy is security-relevant because users may authorize a tool under a narrower trust assumption than what it actually needs, increasing the risk of over-collection of unrelated session cookies and accidental exposure if the cookie jar is mishandled.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This skill handles highly sensitive browser session cookies for a Google account and writes them to disk, but the README's warning language is understated relative to the credential value of those cookies. In this context, those cookies can act as bearer tokens for authenticated sessions, so insufficiently prominent handling guidance increases the chance users store them insecurely, reuse them, or expose them through backups, multi-user systems, logs, or permissive file locations.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill describes capabilities that include browser cookie harvesting, file writes, network access, and shell execution, but it does not declare any explicit tool scope or permission boundaries. In an agent environment, that omission weakens least-privilege controls and can let the skill run with broader access than users expect, especially given that it handles authenticated session material.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The security model claims cookie collection is filtered to Google domains, but earlier content explicitly recommends harvesting ALL browser cookies via CDP. That contradiction is dangerous because CDP browser-level cookie access can expose session tokens for unrelated sites, turning a narrowly scoped backup tool into a broader credential-harvesting mechanism if misused or if the implementation is changed.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
- **Reads:** cookies via the local Chrome DevTools Protocol (localhost:9222) of YOUR
  browser, filtered to `*.google.com` / `*.googleusercontent.com` domains only —
  cookies of banks, shops and other services never leave the browser.
- **Writes:** a Netscape cookie jar (chmod 600) in `/tmp` (or `--jar` path), used only
  to talk to `takeout-download.usercontent.google.com` (i.e. Google). Delete it after
  the run — it is not needed for anything else.
- **Network:** only Google hosts are contacted. No telemetry, no third-party calls.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The example explicitly documents harvesting a full browser cookie jar via CDP and using those session cookies to construct direct CLI download URLs. Session cookies are bearer credentials; exposing or normalizing this workflow without strong warnings, scoping limits, or safer alternatives materially increases the risk of account/session hijacking, unauthorized bulk data access, and accidental credential leakage into logs, scripts, or shared terminals.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This section documents harvesting all browser cookies via CDP, refreshing live session cookies during execution, and using them to automate bulk downloads from Google Takeout. That enables replay of authenticated sessions and bypasses normal interactive controls, creating substantial account-security and privacy risk if reused, logged, or exposed; the surrounding text also normalizes behavior that can trigger account recovery and fraud-detection workflows.

Content

No source excerpt is available for this finding.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Confidence
70% confidence
Finding

Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Content

Scanner excerpt · scripts/cdp_min.py (reported line 31)May include surrounding context.

python
def close_tab(tab_id):
    try:
        urllib.request.urlopen(f"http://127.0.0.1:9222/json/close/{tab_id}", timeout=10).read()
    except Exception:
        pass

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The function retrieves authentication cookies for Google domains directly from a live browser session and returns them as a reusable Cookie header string, with no user confirmation, auditing, or scope restriction beyond the provided URLs. In the context of a bulk-download pipeline explicitly describing cookie harvesting via CDP, this enables session hijacking and unauthorized access to the user's Takeout or Google account data if the value is logged, reused, or exfiltrated.

Content

No source excerpt is available for this finding.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Confidence
70% confidence
Finding

Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Content

Scanner excerpt · scripts/discover_url.py (reported line 19)May include surrounding context.

python
def http_json(path, method="GET"):
    req = urllib.request.Request("http://127.0.0.1:9222" + path, method=method)
    return json.loads(urllib.request.urlopen(req, timeout=10).read())

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script prints and optionally persists a Google Takeout download URL that can function like a bearer token, since such URLs often embed time-limited authorization data. Writing that URL to an arbitrary file increases the chance of credential leakage through shell history, backups, logs, shared directories, or permissive file permissions, enabling unauthorized access to the archive while the link remains valid.

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

python
pass
    print(f"Browser nicht erreichbar — starte neu ...", flush=True)
    if sys.platform == "darwin":
        subprocess.run(["open", "-a", browser_app, "--args",
                        "--remote-debugging-port=9222",
                        "--no-first-run", "--no-default-browser-check"])
    else:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

The script executes linux_cmd via subprocess.run(..., shell=True), and linux_cmd is directly sourced from a CLI parameter. An attacker who can influence that argument can inject arbitrary shell metacharacters and run arbitrary commands with the privileges of the script user; in a skill that already harvests browser cookies via CDP, this compounds the danger significantly.

Content

Scanner excerpt · scripts/takeout_download.py (reported line 57)May include surrounding context.

python
"--remote-debugging-port=9222",
                        "--no-first-run", "--no-default-browser-check"])
    else:
        subprocess.run(linux_cmd or "chromium --remote-debugging-port=9222 --no-first-run",
                       shell=True)
    for _ in range(10):
        time.sleep(3)

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

python
f"--max-overall-download-limit={args.limit}",
                   "--summary-interval=60", "--console-log-level=notice"]
            with open(os.path.join(args.dir, "aria2c_part.log"), "a") as al:
                subprocess.run(cmd, stdout=al, stderr=subprocess.STDOUT)
            if os.path.exists(target) and is_zip(target) and os.path.getsize(target) > 5e9:
                log(logf, f"Teil {i + 1}/{args.total} FERTIG: "
                          f"{os.path.getsize(target) / 1e9:.2f} GB (echtes ZIP)")

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

python
logfile.write(line + "\n")

    def aria2_active():
        return subprocess.run(["pgrep", "-f", "aria2c.*takeout"],
                              capture_output=True).returncode == 0

    log("=== Entpack-Waechter gestartet ===")

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

python
for z in candidates:
                name = os.path.basename(z)
                t0 = time.time()
                r = subprocess.run(["unzip", "-t", "-qq", z], capture_output=True, text=True)
                if r.returncode != 0:
                    log(f"  {name}: INTEGRITAET FEHLGESCHLAGEN (rc={r.returncode}) — bleibt liegen")
                    continue

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
92% confidence
Finding

This code automatically extracts ZIP files from a watched directory into args.dest using external unzip without validating archive entry paths. A malicious ZIP can exploit path traversal (../) or symlink-based extraction behavior to write outside the intended destination, potentially overwriting user files or planting data in sensitive locations; in this bulk-download automation context, automatic unpack-and-delete increases the blast radius because archives are processed immediately with no manual review.

Content

Scanner excerpt · scripts/takeout_unpack_watch.py (reported line 64)May include surrounding context.

python
if r.returncode != 0:
                    log(f"  {name}: INTEGRITAET FEHLGESCHLAGEN (rc={r.returncode}) — bleibt liegen")
                    continue
                r = subprocess.run(["nice", "-n", "15", "unzip", "-o", "-qq", z, "-d", args.dest],
                                   capture_output=True, text=True)
                if r.returncode != 0:
                    log(f"  {name}: entpacken fehlgeschlagen (rc={r.returncode}) — bleibt liegen")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

Natural-language policy violations include forcing a specific language without user opt-in. This file's operational instructions are entirely in German and do not indicate that the skill is German-only, region-specific, or that users can choose another language.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The close_tab function closes a browser tab via the DevTools endpoint, which is a destructive user-environment action. The file provides no confirmation, user-facing log, or explanatory warning around this operation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

Natural-language strings in the module docstring and runtime messages are exclusively German, which imposes a specific language on users. The file does not provide any opt-in, alternative locale, or justification that the skill is intended only for German-speaking users.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code file contains user-facing natural-language documentation in German, and additional argument help text later in the file is also German-only. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale constraint is documented and justified.

Content

No source excerpt is available for this finding.