Back to skill

Security audit

Ganidhuz-FoxX

Security checks for vulnerabilities and agentic risk

Overview

This skill uses your logged-in X/Twitter session cookies as advertised, but it handles login secrets and browser control too broadly for safe default installation.

Install only if you are comfortable giving the skill reusable access to your X/Twitter login session. Treat `secrets/x-cookies.json`, screenshots, extracted text, and any storage-state file as sensitive account data; do not run plans from untrusted sources, and prefer a disposable X account or a version that removes cookie export, limits navigation to X/Twitter, disables write actions by default, and confines outputs to a protected directory.

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)

T09 ยท Insecure Skill Coding Practices

Error
Location
scripts/export-x-cookies.sh:29
Finding
Python Code Injection Through FOXX_COOKIES_OUT<![CDATA[ ## Vulnerability Details **File Location**: `scripts/export-x-cookies.sh`, lines 29-62 **Vulnerability Type**: Environment-variable injection into an unquoted heredoc **Risk Level**: High ### Vulnerable Code ```bash OUT="${FOXX_COOKIES_OUT:-$(dirname "$0")/../secrets/x-cookies.json}" mkdir -p "$(dirname "$OUT")" echo "๐ŸฆŠ Ganidhuz-FoxX: Exporting X cookies from $PROFILE_PATH" pkill -f firefox 2>/dev/null && sleep 2 || true cp "$DB" "$TMP_DB" python3 - << EOF import sqlite3, json conn = sqlite3.connect("$TMP_DB") rows = conn.execute(""" SELECT host, name, value, path, expiry, isSecure, isHttpOnly, sameSite FROM moz_cookies WHERE host LIKE '%twitter%' OR host LIKE '%x.com%' """).fetchall() cookies = [] for r in rows: exp = r[4] if exp > 1e10: exp = int(exp / 1000) elif exp < -1: exp = -1 cookies.append({ "domain": r[0], "name": r[1], "value": r[2], "path": r[3], "expires": exp, "secure": bool(r[5]), "httpOnly": bool(r[6]), "sameSite": ["None","Lax","Strict"][r[7]] if r[7] < 3 else "None" }) conn.close() with open("$OUT", "w") as f: json.dump({"cookies": cookies}, f, indent=2) print(f"โœ… Exported {len(cookies)} cookies -> $OUT") EOF ``` ### Technical Analysis The heredoc delimiter is not quoted, so the shell expands variables throughout the generated Python program. `FOXX_COOKIES_OUT` controls `OUT`, which is inserted directly inside a Python string literal: ```python with open("$OUT", "w") as f: ``` A value containing quotation marks and newline characters can terminate the intended string and introduce additional Python statements. The value is therefore treated as executable Python syntax rather than exclusively as file-path data. The shell quoting applied when assigning and using `OUT` for `mkdir` does not protect its later interpolation into the heredoc. ### Attack Path 1. An attacker gains control over `FOXX_COOKIES_OUT`, such as through a wrapper scr ...[truncated 934 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Quote the heredoc delimiter so that shell expansion is disabled: ```bash python3 - "$TMP_DB" "$OUT" <<'PY' import json import sqlite3 import sys tmp_db = sys.argv[1] output_path = sys.argv[2] conn = sqlite3.connect(tmp_db) # Process cookies here. with open(output_path, "w", encoding="utf-8") as output: json.dump({"cookies": cookies}, output, indent=2) PY ``` - Pass paths through command-line arguments or environment variables and read them as data inside Python. - Never interpolate environment-controlled values into generated source code. - Validate and canonicalize the output path before use. - Add regression tests using paths containing quotes, newlines, backslashes, and shell metacharacters. ]]>

T05 ยท Unauthorized Access and Privilege Escalation

Error
Location
scripts/export-x-cookies.sh:29
Finding
Overbroad Extraction and Insecure Storage of Live Session Cookies<![CDATA[ ## Vulnerability Details **File Location**: `scripts/export-x-cookies.sh`, lines 29-62 **Vulnerability Type**: Plaintext credential exposure, overbroad cookie collection, and unsafe temporary-file handling **Risk Level**: High ### Vulnerable Code ```bash DB="$PROFILE_PATH/cookies.sqlite" TMP_DB="/tmp/foxx-cookies-copy.sqlite" OUT="${FOXX_COOKIES_OUT:-$(dirname "$0")/../secrets/x-cookies.json}" mkdir -p "$(dirname "$OUT")" echo "๐ŸฆŠ Ganidhuz-FoxX: Exporting X cookies from $PROFILE_PATH" pkill -f firefox 2>/dev/null && sleep 2 || true cp "$DB" "$TMP_DB" python3 - << EOF import sqlite3, json conn = sqlite3.connect("$TMP_DB") rows = conn.execute(""" SELECT host, name, value, path, expiry, isSecure, isHttpOnly, sameSite FROM moz_cookies WHERE host LIKE '%twitter%' OR host LIKE '%x.com%' """).fetchall() cookies = [] for r in rows: exp = r[4] if exp > 1e10: exp = int(exp / 1000) elif exp < -1: exp = -1 cookies.append({ "domain": r[0], "name": r[1], "value": r[2], "path": r[3], "expires": exp, "secure": bool(r[5]), "httpOnly": bool(r[6]), "sameSite": ["None","Lax","Strict"][r[7]] if r[7] < 3 else "None" }) conn.close() with open("$OUT", "w") as f: json.dump({"cookies": cookies}, f, indent=2) print(f"โœ… Exported {len(cookies)} cookies -> $OUT") EOF ``` ### Technical Analysis The script copies Firefox's cookie database to a predictable global path, `/tmp/foxx-cookies-copy.sqlite`. It neither creates the file securely nor removes it after processing. This creates several risks: - A local attacker may pre-create the path as a symbolic link, potentially redirecting the privileged copy operation. - Other local processes may access residual cookie data depending on ownership and process context. - The copied database remains in `/tmp` after the script exits. - Concurrent executions use the same path and can interfere with one another. The exported JSON contains raw cookie ...[truncated 1982 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Set a restrictive umask before creating any sensitive file: ```bash umask 077 ``` - Replace the predictable temporary filename with `mktemp` and guarantee cleanup: ```bash TMP_DB="$(mktemp "${TMPDIR:-/tmp}/foxx-cookies.XXXXXX.sqlite")" trap 'rm -f -- "$TMP_DB"' EXIT ``` - Create the output file with exclusive creation and mode `0600`; reject symbolic links and unsafe pre-existing files. - Restrict the SQL query to exact intended domain boundaries, for example: ```sql WHERE host IN ('x.com', '.x.com', 'twitter.com', '.twitter.com') ``` - Export only cookie names strictly required for the authenticated use case, where technically possible. - Warn users that the output is equivalent to an authentication credential and must not be committed, shared, logged, or stored in a world-readable directory. - Add the secrets directory and cookie artifacts to `.gitignore`. - Delete exported cookies immediately when no longer required, or use an in-memory transfer rather than persistent plaintext storage. ]]>

T05 ยท Unauthorized Access and Privilege Escalation

Error
Location
scripts/playwright-firefox-control.py:17
Finding
Unrestricted Authenticated Browser Automation Exceeds the Declared Read-Oriented Scope<![CDATA[ ## Vulnerability Details **File Location**: `scripts/playwright-firefox-control.py`, lines 17-157 **Vulnerability Type**: Missing domain and action authorization controls **Risk Level**: High ### Vulnerable Code ```python def run_step(page, step: dict) -> dict: action = step.get("action") if action == "goto": url = step["url"] wait_until = step.get("wait_until", "domcontentloaded") page.goto(url, wait_until=wait_until) return {"action": action, "ok": True, "url": page.url} if action == "click": page.locator(step["selector"]).first.click(timeout=step.get("timeout_ms", 10000)) return {"action": action, "ok": True} if action == "fill": page.locator(step["selector"]).first.fill( step.get("text", ""), timeout=step.get("timeout_ms", 10000) ) return {"action": action, "ok": True} if action == "type": page.locator(step["selector"]).first.type( step.get("text", ""), delay=step.get("delay_ms", 50), timeout=step.get("timeout_ms", 10000), ) return {"action": action, "ok": True} if action == "press": page.keyboard.press(step["key"]) return {"action": action, "ok": True} ``` ```python initial_url = plan.get("url", "about:blank") steps = plan.get("steps", []) with sync_playwright() as p: browser = p.firefox.launch(headless=headless) context = browser.new_context() # Inject cookies from file if provided in plan cookies_path = plan.get("cookies_path") if cookies_path and os.path.exists(cookies_path): import json as _json with open(cookies_path) as cf: cookie_data = _json.load(cf) context.add_cookies(cookie_data.get("cookies", [])) page = context.new_page() page.goto(initial_url) for step in steps: try: step_result = run_step(page, step) results["steps"].append(step_res ...[truncated 2066 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Validate every URL before navigation using parsed scheme and exact hostname checks. - Permit only HTTPS URLs on an explicit allowlist such as `x.com`, `www.x.com`, `twitter.com`, and approved subdomains. - Revalidate `page.url` after redirects. - Provide a read-only operating mode that disallows `click`, `fill`, `type`, and `press` by default. - Permit state-changing actions only after explicit, per-action user confirmation that displays the destination, selector, and entered text. - Validate plans against a strict JSON schema and reject unknown fields, actions, types, and excessive timeout values. - Separate read-only extraction from account-modifying automation. - Treat plan files as trusted executable instructions and clearly document that they must not be accepted from untrusted sources. - Consider using an isolated account with minimal privileges instead of the user's primary session. ]]>

T09 ยท Insecure Skill Coding Practices

Warning
Location
scripts/playwright-firefox-control.py:47
Finding
Plan-Controlled Arbitrary File Writes and Authentication State Export<![CDATA[ ## Vulnerability Details **File Location**: `scripts/playwright-firefox-control.py`, lines 47-174 **Vulnerability Type**: Unrestricted filesystem paths and plaintext session-state export **Risk Level**: Medium ### Vulnerable Code ```python if action == "screenshot": path = step.get("path", "/tmp/firefox-openclaw-step.png") Path(path).parent.mkdir(parents=True, exist_ok=True) page.screenshot(path=path, full_page=step.get("full_page", False)) return {"action": action, "ok": True, "path": path} ``` ```python profile_dir = plan.get("profile_dir", args.profile_dir) Path(profile_dir).mkdir(parents=True, exist_ok=True) ``` ```python validation_path = plan.get( "validation_screenshot", "/tmp/firefox-openclaw-validate.png" ) page.screenshot(path=validation_path) results["validation_screenshot"] = validation_path ``` ```python if plan.get("storage_state_path"): context.storage_state(path=plan["storage_state_path"]) ``` ```python if args.output == "-": print(payload) else: Path(args.output).parent.mkdir(parents=True, exist_ok=True) with open(args.output, "w", encoding="utf-8") as f: f.write(payload + "\n") ``` ### Technical Analysis Several paths are accepted without confinement to an application-owned output directory. Plan-controlled screenshot paths, validation paths, profile directories, and storage-state paths can target arbitrary locations writable by the invoking user. `context.storage_state()` is particularly sensitive because the resulting file may contain reusable cookies and other browser-origin state. The code does not apply restrictive permissions, reject symbolic links, require exclusive creation, or warn before exporting session material. The output path is command-line controlled rather than plan controlled, but it is likewise created and overwritten without path confinement or symlink protections. ### Attack Path 1. An attacker supplies or influences a plan executed by a more privileged ...[truncated 1036 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Resolve every output path and require it to remain beneath a dedicated application-owned directory. - Reject absolute paths, `..` traversal, and symbolic links supplied by plans. - Create sensitive files with exclusive creation and mode `0600`. - Disable `storage_state_path` by default and require explicit informed authorization before exporting browser state. - Store session-state exports only in a protected secrets directory and delete them after use. - Use separate APIs for ordinary screenshots and sensitive session export. - Validate filename extensions and enforce reasonable file-size and directory limits. - Avoid creating plan-selected profile directories when the current implementation does not actually use them to launch a persistent context. ]]>

T08 ยท Insecure Dependencies

Warning
Location
SKILL.md:17
Finding
Unpinned Playwright and Browser Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 17 **Vulnerability Type**: Unpinned executable third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash - Playwright: `pip install playwright && playwright install firefox` ``` ### Technical Analysis The installation instruction resolves the current Playwright release at installation time rather than a reviewed version. Package installation executes package-controlled build or installation behavior, and `playwright install firefox` downloads an additional browser payload selected by the resolved Playwright version. No version constraint, hash verification, lockfile, or trusted package-index policy is specified. Consequently, two installations performed at different times may execute different dependency and browser code. This is a supply-chain hardening issue; the audited files do not show an intentionally malicious dependency name or external payload URL. ### Attack Path 1. A user follows the documented setup instructions. 2. `pip` resolves the latest package available from its configured index. 3. A compromised release, compromised package index, or unsafe index configuration supplies altered package content. 4. Installation-time package behavior executes with the installing user's privileges. 5. The subsequent Playwright command downloads and installs the browser artifact associated with that mutable package version. ### Impact Assessment A compromised package or browser artifact could execute code as the installing user and gain access to project data, browser sessions, cookie exports, and other user-accessible files. The practical likelihood depends on the integrity of the configured package index and upstream distribution infrastructure. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Pin Playwright to an explicitly reviewed version. - Maintain dependencies in a lockfile with cryptographic hashes. - Install from an explicitly configured trusted package index. - Use reproducible build or deployment images containing pre-verified dependencies. - Pin and verify the corresponding Playwright browser artifact. - Run dependency vulnerability and provenance checks during CI. - Periodically update pins through a controlled review process rather than resolving mutable latest versions during deployment. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documented behavior frames the skill as an X/Twitter browsing helper, but the plan format and supported actions enable generic browser automation, arbitrary URL navigation, selector-based content extraction, screenshot capture, cookie injection, and storage-state export. In the context of a logged-in browser session, that broader capability can be abused to access unrelated sites, harvest authenticated content, or persist session material beyond the stated purpose.

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

High
Category
YARA Match
Content
#!/bin/bash
# Ganidhuz-FoxX: Export X/Twitter cookies from real Firefox snap profile
# Run this when session expires. Close Firefox first!
# 
# Config via env vars:
#   FIREFOX_PROFILE_PATH  - path to Firefox profile dir (default: auto-detect)
#   FOXX_COOKIES_OUT      - output path for cookies JSON (default: ./secrets/x-cookies.json)

set -e

# Auto-detect Firefox profile
if [ -n "$FIREFOX_PROFILE_PATH" ]; then
    PROFILE_PATH="$FIREFOX_PROFILE_PATH"
elif [ -f "$HOME/snap/firefox/common/.mozilla/firefox/profiles.ini" ]; then
    PROFILE_DIR="$HOME/snap/firefox/common/.mozilla/firefox"
    PROFILE_NAME=$(grep "^Path=" "$PROFILE_DIR/profi
Confidence
97% confidence
Finding
The core behavior of the skill is to harvest authenticated cookies from a real Firefox profile and inject/reuse them to access X/Twitter without an API. In the context of an agent skill, this is highly dangerous because session-cookie extraction is a classic credential-theft pattern that can enable account impersonation and bypass normal authentication controls.

Missing User Warnings

High
Confidence
98% confidence
Finding
The script reads authenticated Twitter/X cookies from the Firefox profile database and writes them in plaintext JSON to disk. These cookies can grant session access equivalent to the logged-in user, so persisting them in a reusable file materially increases the risk of account takeover if the file is exposed, copied, or mishandled.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill documents capabilities that read environment variables, read files, and write files, but it declares no explicit tool scope or permission boundaries. In a skill that handles exported authenticated cookies and writes screenshots/session state to disk, missing scope declarations increases the chance of overbroad access and unsafe use of sensitive local data.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The setup instructions tell users to export real authenticated X/Twitter cookies to a JSON file but do not prominently warn that these cookies are equivalent to session credentials. Because the skill relies on cookie injection, mishandling that file can allow account takeover or unauthorized access if the file is copied, logged, or stored insecurely.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill supports screenshots and selector-based content extraction while operating inside an authenticated social-media session, but it does not warn that outputs may capture private messages, account data, recommendations, or other sensitive content. This omission raises the risk of accidental data exposure through saved images, logs, or downstream processing.

Context Window Stuffing

Medium
Category
Memory Poisoning
Content
- `goto` - navigate to URL
- `click` - click element by selector
- `fill` - fill input by selector
- `type` - type text with delay
- `press` - press keyboard key
- `wait` - wait ms
Confidence
85% confidence
Finding
Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The script unconditionally runs `pkill -f firefox`, forcibly terminating Firefox processes system-wide without user confirmation. While likely intended to avoid SQLite lock issues, this can disrupt unrelated user activity and cause data loss, and it exceeds a minimally safe cookie-export workflow.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Firefox is terminated without explicit confirmation despite the script comment only advising the user to close it first. Abruptly killing the browser can interrupt active sessions, lose unsaved work, and may terminate unrelated Firefox instances not associated with the target profile.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The script exposes a generic browser automation primitive set including arbitrary navigation, clicking, typing, key presses, waits, screenshots, and content extraction. Although described as an X/Twitter browsing skill, these actions can drive any site reachable by Firefox, enabling broader account interaction or data access than the manifest suggests. In the context of a real logged-in browser session, this scope mismatch materially increases risk.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The script will ingest cookies from any local file path supplied in the plan and inject them into the browser context. This permits use of arbitrary stolen or unrelated cookies and broadens the skill from viewing X/Twitter to importing external authenticated sessions, which is especially dangerous given the stated use of a real logged-in Firefox workflow. It also enables local sensitive-file access patterns and unauthorized session manipulation.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
Writing storage state to an attacker-controlled path enables export and persistence of authenticated browser session material beyond simple browsing. In a skill that operates with a real logged-in session, session export can allow replay or long-term reuse of credentials/cookies and exceeds the declared functionality. This makes compromise of the user's account or cross-session tracking materially easier.

Static analysis

No suspicious patterns detected.