Back to skill

Security audit

Tweet Share Card

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate tweet-card purpose, but its screenshot helper can turn a crafted tweet URL into local AppleScript execution and may capture more browser content than intended.

Review this skill before installing. It is not clearly malicious, but only use it with trusted tweet URLs and a dedicated browser profile. Avoid running it on a normal logged-in Chrome window until the URL is strictly validated before browser navigation, AppleScript input is safely passed or escaped, and uncropped intermediate screenshots are deleted automatically.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/capture_visible_tweet.py:11
Finding
AppleScript Injection Through an Unescaped URL Argument<![CDATA[ ## Vulnerability Details **File Location**: `scripts/capture_visible_tweet.py`, lines 11-27 **Vulnerability Type**: AppleScript injection **Risk Level**: High ### Vulnerable Code ```python url = sys.argv[1] out = Path(sys.argv[2]).expanduser().resolve() out.parent.mkdir(parents=True, exist_ok=True) script = f''' tell application "Google Chrome" activate if (count of windows) = 0 then make new window tell front window set URL of active tab to "{url}" end tell delay 2 set b to bounds of front window set u to URL of active tab of front window return u & "\n" & ((item 1 of b as text) & "," & (item 2 of b as text) & "," & (item 3 of b as text) & "," & (item 4 of b as text)) end tell ''' ``` ### Technical Analysis The first command-line argument is treated as untrusted URL input and directly interpolated into executable AppleScript source. No escaping, encoding, or structural URL validation occurs before the generated script is passed to `osascript`. An attacker can supply a value containing a double quote followed by AppleScript statements. The quote can terminate the intended URL string, after which the injected statements become part of the generated script. This is a code-injection boundary rather than merely malformed URL handling. The later check of Chrome's current URL cannot mitigate this issue because the generated AppleScript has already been parsed and executed by that point. ### Attack Path 1. An attacker submits a crafted value where a tweet URL is expected. 2. The agent passes that value as the first argument to `capture_visible_tweet.py`. 3. The value is inserted into the `set URL of active tab to "..."` statement without escaping. 4. Embedded quote characters terminate the intended AppleScript string. 5. Attacker-supplied AppleScript statements are parsed and executed by `osascript`. 6. The injected code runs with the permissions of the user account executing the skill. ### Impact Assessment Successful exploita ...[truncated 498 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not interpolate the URL into AppleScript source. 2. Pass the URL as a positional argument to `osascript` and retrieve it through an `on run argv` handler: ```python script = r''' on run argv set targetURL to item 1 of argv tell application "Google Chrome" activate if (count of windows) = 0 then make new window tell front window set URL of active tab to targetURL end tell end tell end run ''' subprocess.check_call(["osascript", "-e", script, url]) ``` 3. Before invoking AppleScript, parse the URL with `urllib.parse.urlsplit`. 4. Require the `https` scheme and an exact normalized hostname allowlist such as `x.com`, `www.x.com`, `twitter.com`, and `www.twitter.com`. 5. Reject embedded credentials, unexpected ports, control characters, and URLs that do not match an expected post path. 6. Add regression tests containing quotes, newlines, backslashes, Unicode hostnames, credentials, and deceptive hostnames to verify that input can never modify the script structure. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/capture_visible_tweet.py:20
Finding
Arbitrary Browser Navigation Due to Post-Navigation Substring Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/capture_visible_tweet.py`, lines 20-31 **Vulnerability Type**: Improper URL validation **Risk Level**: Medium ### Vulnerable Code ```python set URL of active tab to "{url}" end tell delay 2 set b to bounds of front window set u to URL of active tab of front window return u & "\n" & ((item 1 of b as text) & "," & (item 2 of b as text) & "," & (item 3 of b as text) & "," & (item 4 of b as text)) end tell ''' res = subprocess.check_output(['osascript', '-e', script]).decode().splitlines() current_url = res[0].strip() if 'x.com/' not in current_url and 'twitter.com/' not in current_url: raise SystemExit(f'Unexpected URL after navigation: {current_url}') ``` ### Technical Analysis The browser is instructed to navigate to the supplied URL before any allowlist check is performed. Consequently, rejecting the URL afterward does not prevent the browser from contacting an arbitrary site or processing attacker-controlled content. The post-navigation validation is also based on substring presence rather than parsed scheme and hostname equality. An attacker-controlled URL may contain `x.com/` or `twitter.com/` in its path, query, fragment, or user-information component while its actual destination host remains unrelated. Because this code uses an existing logged-in Chrome session, arbitrary navigation can expose that session to phishing pages, browser exploits, unwanted downloads, and other web-origin attacks. ### Attack Path 1. An attacker provides a URL under an attacker-controlled hostname. 2. The URL includes an allowed substring such as `x.com/` somewhere outside the hostname. 3. The script directs the active Chrome tab to the URL before validating it. 4. Chrome connects to and renders the attacker-controlled site in the user's existing browser session. 5. The weak substring check may accept the resulting URL if the allowed text remains present. 6. The skill then captures and proces ...[truncated 686 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Validate the destination before any browser interaction: ```python from urllib.parse import urlsplit parsed = urlsplit(url) allowed_hosts = {"x.com", "www.x.com", "twitter.com", "www.twitter.com"} if parsed.scheme.lower() != "https": raise SystemExit("Only HTTPS URLs are allowed") if parsed.hostname is None or parsed.hostname.lower() not in allowed_hosts: raise SystemExit("Only approved X/Twitter hosts are allowed") if parsed.username is not None or parsed.password is not None: raise SystemExit("URLs containing credentials are not allowed") if parsed.port not in (None, 443): raise SystemExit("Unexpected URL port") ``` Additionally: 1. Validate the expected tweet/status path format. 2. Normalize the hostname before comparison and use exact equality, not substring checks. 3. Define a redirect policy. After navigation, parse and validate the final URL using the same exact-host rules. 4. If the final URL is invalid, close or reset the dedicated tab immediately. 5. Use a separate browser profile with minimal permissions and no unrelated authenticated sessions. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/capture_visible_tweet.py:15
Finding
Overbroad Browser Capture and Persistent Storage of Uncropped Private Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/capture_visible_tweet.py`, lines 15-39 **Vulnerability Type**: Excessive data capture and unsafe intermediate-file retention **Risk Level**: Medium ### Vulnerable Code ```python script = f''' tell application "Google Chrome" activate if (count of windows) = 0 then make new window tell front window set URL of active tab to "{url}" end tell delay 2 set b to bounds of front window set u to URL of active tab of front window return u & "\n" & ((item 1 of b as text) & "," & (item 2 of b as text) & "," & (item 3 of b as text) & "," & (item 4 of b as text)) end tell ''' res = subprocess.check_output(['osascript', '-e', script]).decode().splitlines() current_url = res[0].strip() if 'x.com/' not in current_url and 'twitter.com/' not in current_url: raise SystemExit(f'Unexpected URL after navigation: {current_url}') left, top, right, bottom = map(int, res[1].split(',')) raw = out.parent / (out.stem + '.window.png') subprocess.check_call(['/usr/sbin/screencapture', '-x', '-R', f'{left},{top},{right-left},{bottom-top}', str(raw)]) img = Image.open(raw).convert('RGBA') W, H = img.size # Main tweet column crop for desktop X layout; conservative and left-column focused. crop = img.crop((int(W * 0.07), int(H * 0.10), int(W * 0.62), int(H * 0.73))) crop.save(out) ``` ### Technical Analysis The script targets whichever Google Chrome window is currently frontmost rather than identifying a dedicated, isolated profile or window. It then captures the bounds of the entire Chrome window, although the requested output only requires the tweet content area. The full-window screenshot is written to a predictable path derived from the output filename: ```text <output-directory>/<output-stem>.window.png ``` After creating the cropped output, the script does not delete this raw file. The uncropped screenshot can therefore persist beyond the skill invocation and may include browser chrome, account inf ...[truncated 1422 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Launch or explicitly select a dedicated Chrome profile and window created solely for this skill. Do not operate on whichever window is frontmost. 2. Verify the profile, window, tab, and final origin before taking a screenshot. 3. Capture only the required content element or the smallest possible screen region rather than the entire browser window. 4. Store unavoidable intermediate images in a securely created temporary directory with restrictive permissions. 5. Delete raw screenshots in a `finally` block, including after failures: ```python import tempfile with tempfile.TemporaryDirectory(prefix="tweet-capture-") as tmp_dir: raw = Path(tmp_dir) / "window.png" subprocess.check_call([ "/usr/sbin/screencapture", "-x", "-R", f"{left},{top},{right-left},{bottom-top}", str(raw), ]) with Image.open(raw) as source: img = source.convert("RGBA") crop = img.crop(crop_bounds) crop.save(out) ``` 6. Apply restrictive filesystem permissions to output directories where sensitive screenshots may be written. 7. Avoid predictable persistent intermediate filenames. 8. Add checks that abort capture when the expected dedicated browser context or approved X/Twitter origin cannot be confirmed. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return u & "\n" & ((item 1 of b as text) & "," & (item 2 of b as text) & "," & (item 3 of b as text) & "," & (item 4 of b as text))
end tell
'''
res = subprocess.check_output(['osascript', '-e', script]).decode().splitlines()
current_url = res[0].strip()
if 'x.com/' not in current_url and 'twitter.com/' not in current_url:
    raise SystemExit(f'Unexpected URL after navigation: {current_url}')
Confidence
95% confidence
Finding
The script interpolates the untrusted `tweet_url` directly into AppleScript source and executes it via `osascript`. Because AppleScript string literals can be broken by crafted input, an attacker can inject additional AppleScript commands, potentially controlling local applications or executing shell commands through AppleScript on the host.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
raise SystemExit(f'Unexpected URL after navigation: {current_url}')
left, top, right, bottom = map(int, res[1].split(','))
raw = out.parent / (out.stem + '.window.png')
subprocess.check_call(['/usr/sbin/screencapture', '-x', '-R', f'{left},{top},{right-left},{bottom-top}', str(raw)])
img = Image.open(raw).convert('RGBA')
W, H = img.size
# Main tweet column crop for desktop X layout; conservative and left-column focused.
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The README states that the skill reads tweet content and may include metrics from external X/Twitter links, but it does not disclose this data-fetching behavior as a user-facing warning or note about external content processing. This is primarily a transparency and privacy-consent issue: users may not realize the skill will retrieve and process remote post data and associated metadata.

Static analysis

No suspicious patterns detected.