Back to skill

Security audit

Follow News

Security checks for vulnerabilities and agentic risk

Overview

This news-digest skill is mostly coherent, but it gives itself unusually broad local authority for browser sessions, credentials, and OpenCLI updates.

Review before installing. Use narrowly scoped API tokens, disable OpenCLI auto-update and browser cleanup unless you explicitly want them, avoid running it against a sensitive live browser profile, and verify any scheduled delivery destination before enabling recurring digests.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (26)

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not window_ids or sys.platform != "darwin" or not shutil.which("osascript"):
        return

    result = subprocess.run(
        ["osascript", "-e", CHROME_WINDOW_CLOSE_SCRIPT] + window_ids,
        capture_output=True,
        text=True,
Confidence
86% confidence
Finding
This subprocess closes Chrome windows using IDs gathered from a prior enumeration step, which gives the skill authority to modify local browser state unrelated to its stated purpose. Even without shell injection, that is an unjustified local-impact capability: mistakes or abuse could close user windows/tabs and disrupt active sessions or work.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def _run_opencli_version_command(binary: str, args: List[str], timeout: int = 10) -> subprocess.CompletedProcess:
    """Run one OpenCLI version command without raising."""
    try:
        return subprocess.run(
            [binary] + args,
            capture_output=True,
            text=True,
Confidence
89% confidence
Finding
This runs an executable chosen from OPENCLI_BIN or PATH, so the program trusts external environment/path resolution to decide what binary gets executed. In an agent or shared environment, a malicious or trojaned opencli binary could be executed during a routine version check, leading to arbitrary code execution under the agent's privileges.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def _run_opencli_update_command(binary: str, args: List[str], timeout: int = 120) -> subprocess.CompletedProcess:
    """Run one OpenCLI update command variant."""
    try:
        return subprocess.run(
            [binary] + args,
            capture_output=True,
            text=True,
Confidence
96% confidence
Finding
This code executes OpenCLI update commands, including command variants partially influenced by OPENCLI_UPDATE_COMMAND, causing the script to run external subcommands beyond tweet collection. Combined with trust in OPENCLI_BIN/PATH, this can trigger arbitrary executable behavior and even self-modification of the local toolchain.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def _run_command(self, args: List[str], timeout: int = OPENCLI_TIMEOUT) -> subprocess.CompletedProcess:
        try:
            return subprocess.run(
                [self.command] + args,
                capture_output=True,
                text=True,
Confidence
93% confidence
Finding
This helper is the main execution path for OpenCLI commands and invokes whatever binary is stored in self.command, which ultimately comes from environment or PATH resolution. That creates an arbitrary local executable trust boundary: a compromised binary or path hijack would let an attacker run code whenever tweet fetching occurs.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The README documents capabilities to auto-update an external tool and manipulate local browser state by closing tabs and Chrome windows. For a news-digest skill, these behaviors expand from passive content collection into host/browser control, which increases the chance of unwanted local side effects and abuse if the agent executes them automatically.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The skill relies on external executables such as `opencli` and `yt-dlp` for fetching and transcript collection, which introduces subprocess execution and trust in binaries outside the skill itself. In an agent context, that broadens the attack surface through binary path hijacking, unsafe invocation, or execution of tools with broader system access than users expect from a digest generator.

Context-Inappropriate Capability

Medium
Confidence
86% confidence
Finding
The README documents use of OpenCLI to reuse existing logged-in browser sessions for X/Twitter and Xiaoyuzhou. That expands the skill from simple news aggregation into browser-mediated access to authenticated accounts, which increases risk of unintended access to private data, session misuse, or overbroad actions if the helper tool is compromised or misused. In the context of a news-digest skill, this capability is broader than strictly necessary.

Context-Inappropriate Capability

Medium
Confidence
82% confidence
Finding
The README states the skill may close browser tabs and Chrome windows created during OpenCLI runs. Even if intended as cleanup, this is endpoint-control behavior affecting the user's local environment and can cause disruption, data loss in unsaved tabs, or user confusion if scope tracking is imperfect. For a news-digest skill, that level of browser control is not obviously necessary and increases operational risk.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The security notes claim that no files outside the workspace are accessed, but the same document allows use of external key files via GH_APP_KEY_FILE and delegated credential stores like gh/OpenCLI. This inaccurate assurance can mislead reviewers about where sensitive material may be read from and whether external secrets or session state are involved.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The script generates a GitHub App JWT and exchanges it for an installation access token by invoking `openssl` and calling the GitHub API. That adds credential-handling and token-minting behavior beyond simple public news retrieval, which increases the blast radius if the script is run in a privileged environment.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The token resolution logic automatically probes local environment secrets and a private key file, then falls back to `gh auth token`. For a news aggregation skill, silently broadening into credential discovery and reuse is risky because it can leverage whatever GitHub privileges happen to be present on the host.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The script is described as fetching podcast and YouTube metadata, but it can also download and persist full transcripts in output and cache files. This creates unnecessary data collection and retention risk, especially if operators expect metadata-only behavior and transcripts may include sensitive or copyrighted content.

Intent-Code Divergence

Medium
Confidence
88% confidence
Finding
The top-level documentation states the script fetches episode metadata, but the implementation includes transcript download paths via `yt-dlp` and `opencli`. This mismatch can mislead users and reviewers about what data is retrieved and stored, increasing privacy, compliance, and operational risk.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
A news-digest skill should fetch data, not self-update or dispatch broad maintenance subcommands on a local CLI. The OpenCLI update logic materially expands capability from network retrieval into local software modification and execution, which increases the blast radius if configuration, PATH resolution, or the external tool is compromised.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The embedded AppleScript inspects Chrome windows/tabs and later enables closing them, which is unrelated to generating a tech news digest. This is dangerous because it reaches into user browser state, exposing privacy-sensitive browsing context and permitting destructive local actions outside the skill's stated scope.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
These tests confirm the skill supports OpenCLI auto-update behavior, which is outside the declared purpose of generating news digests. Auto-updating an external CLI introduces a supply-chain and integrity risk because the skill can change or replace an executable at runtime, expanding capabilities beyond content collection.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The tests show the skill enumerates and closes browser tabs and Chrome windows, behavior not described in the manifest and unrelated to digest generation. Manipulating a user's browser state can disrupt active sessions, destroy user context, and create a covert side effect surface that is much broader than expected for a news tool.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
Automatic self-updating of OpenCLI is an unjustified capability for a news-digest skill because it allows runtime modification of a dependency without user review. In this context, that means the skill can change the behavior of tooling it depends on, potentially pulling in malicious or compromised code from upstream and bypassing normal change-management controls.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
Closing browser tabs and Chrome windows is context-inappropriate for the declared purpose and gives the skill destructive control over local user applications. Even if intended as cleanup, this can terminate user work, affect unrelated sessions, and be abused to conceal traces of browsing or automation activity.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The code accesses sensitive authentication material and performs a token exchange without a user-facing consent step or prominent warning. In an agent skill context, that is dangerous because users may expect content fetching, not local secret use and privileged API authentication.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
When transcript support is enabled, the script sends episode URLs to `yt-dlp` and may download subtitle/transcript content without any clear user-facing disclosure at the point of execution. In this skill context, that broadens collection beyond simple feed metadata and may surprise operators who are only expecting article-like summaries.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The `opencli` transcript path performs external fetching and then reads generated transcript files from disk, expanding the trust boundary to a third-party tool and its outputs. Although the code includes a path traversal check, the overall behavior still introduces undisclosed data retrieval and local persistence of transcript content.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The backend constructor can automatically trigger OpenCLI self-update during normal operation, without a point-of-action confirmation from the user. In a skill whose purpose is tweet retrieval, silently updating local software is an unexpected privileged side effect that can change code on disk and execute additional installer logic.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The tests indicate OpenCLI update commands can be invoked automatically, yet there is no visible evidence here of strong user disclosure or confirmation requirements. Silent background updates reduce transparency and make supply-chain changes harder for operators to detect or review.

Unvalidated Output Injection

High
Category
Output Handling
Content
episode["link"],
        ]
        try:
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
Confidence
91% confidence
Finding
The plan proposes passing an untrusted episode URL directly to an external tool (`yt-dlp`) via `subprocess.run`. Although `shell=True` is not used, this still creates an output-handling and argument-injection style risk because attacker-controlled URLs can cause the helper tool to access unexpected resources, process maliciously crafted inputs, or behave dangerously if it interprets special URL forms or protocols.

Static analysis

Detected: suspicious.dynamic_code_execution, suspicious.exposed_secret_literal

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/doctor.py:31

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_acceptance_digest.py:39

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_config_editor_server.py:26

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_config.py:36

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_doctor.py:16

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_fetch_podcast.py:19

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_fetch_twitter_opencli.py:26

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_merge.py:24

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_run_pipeline.py:12

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_source_health.py:16

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_summarize_merged.py:18

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/fetch-github.py:515