Back to skill

Security audit

RSS-Brew

Security checks for vulnerabilities and agentic risk

Overview

This RSS digest skill mostly matches its stated purpose, but it needs review because its documented dry-run can still commit pipeline state and it uses broad network and credential flows.

Review this before installing on production data. Use a throwaway data root for dry-run because it is not actually no-write, keep feed sources trusted, avoid custom DEEPSEEK_BASE_URL values unless you control the endpoint, and expect article titles/content plus provider API keys to be used for external model/search services. Pin dependencies before operational use.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/phase_a_score.py:68
Finding
Configurable API endpoint can disclose the DeepSeek credential and article content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/phase_a_score.py:68-105`; duplicated in `app/src/rss_brew/compat/phase_a_score.py:68-105` **Vulnerability Type**: Unvalidated credential-bearing API destination **Risk Level**: Medium ### Vulnerable Code ```python def _load_phase_a_config() -> PhaseAConfig: api_key = os.getenv("DEEPSEEK_API_KEY", "").strip() base_url = os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com/v1").strip() model = os.getenv("DEEPSEEK_MODEL", "deepseek-reasoner").strip() or "deepseek-reasoner" timeout = float(os.getenv("DEEPSEEK_TIMEOUT_SECONDS", "60")) retries = int(os.getenv("DEEPSEEK_RETRY_COUNT", "2")) return PhaseAConfig( api_key=api_key, base_url=base_url, model=model, timeout=timeout, retries=max(0, retries), ) def _build_client(config: PhaseAConfig) -> Any: if not config.get("api_key"): raise RuntimeError("DEEPSEEK_API_KEY is required unless --mock is used") try: from openai import OpenAI except Exception as exc: raise RuntimeError("openai package is required for direct DeepSeek API mode") from exc return OpenAI( api_key=config["api_key"], base_url=config["base_url"], timeout=config["timeout"], ) def _call_deepseek(prompt: str, config: PhaseAConfig, client: Any) -> str: attempts = config["retries"] + 1 last_err: Optional[Exception] = None for attempt in range(1, attempts + 1): try: resp = client.chat.completions.create( model=config["model"], messages=[ {"role": "system", "content": SYSTEM}, {"role": "user", "content": prompt}, ], temperature=0, ) ``` ### Technical Analysis `DEEPSEEK_BASE_URL` is taken directly from the process environment and supplied to the OpenAI-compatible client without validating its scheme or hostname ...[truncated 1732 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Default to the fixed endpoint `https://api.deepseek.com/v1`. 2. Parse the configured URL and reject non-HTTPS schemes, embedded credentials, fragments, and unexpected ports. 3. Maintain an explicit allowlist of trusted provider hostnames. If arbitrary compatible providers are required, use separate provider-specific credential variables rather than automatically forwarding `DEEPSEEK_API_KEY`. 4. Require an explicit opt-in for custom endpoints and display the selected destination before the first credential-bearing request. 5. Prevent redirects to unapproved hosts and revalidate the destination after redirects. 6. Ensure logs never include API keys or authorization headers. 7. Apply the same validation to the compatibility copy under `app/src/rss_brew/compat/`. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/core_pipeline.py:37
Finding
Unrestricted feed and article fetching permits server-side request forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/core_pipeline.py:37-39, 246-258, 376-413`; equivalent behavior in `app/src/rss_brew/compat/core_pipeline.py`; direct fetch helper in `scripts/fetch_rss.py:6-11` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: Medium ### Vulnerable Code ```python class Source(BaseModel): name: str url: str deepset_eligible: bool = True ``` ```python def extract_text( url: str, retries: int = 2, retry_delay: float = 0.6, ) -> Optional[str]: for attempt in range(retries + 1): downloaded = trafilatura.fetch_url(url) if downloaded: text = trafilatura.extract( downloaded, include_comments=False, include_tables=False, include_images=False, favor_recall=False, ) if text: return text.strip() if attempt < retries: time.sleep(retry_delay) return None ``` ```python for source in sources: feed = feedparser.parse(source.url) source_stat = source_stats[source.name] for entry in feed.entries: stats["total_entries"] += 1 url = entry.get("link") title = entry.get("title") if not url or not title: stats["invalid"] += 1 continue # ... canonical_url = canonicalize_url(url) # ... text = extract_text(canonical_url) ``` The standalone helper has the same unrestricted behavior: ```python def parse_feed(url): articles = [] try: req = urllib.request.Request( url, headers={'User-Agent': 'Mozilla/5.0'}, ) with urllib.request.urlopen(req, timeout=10) as response: xml_data = response.read() ``` ### Technical Analysis The pipeline must make outbound network requests to fetch RSS feeds and public articles, but it accepts destinations without enforci ...[truncated 2013 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only `http` and `https` URLs and reject URLs containing user information or malformed hostnames. 2. Resolve destination hostnames before connecting and reject all loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 addresses. 3. Explicitly block cloud metadata destinations, including `169.254.169.254` and platform-specific metadata hostnames. 4. Disable redirects or validate the scheme, hostname, resolved addresses, and port after every redirect. 5. Consider an allowlist of trusted feed domains. At minimum, independently validate article-link destinations. 6. Protect against DNS rebinding by connecting to the validated address and ensuring the HTTP host and TLS certificate still match the intended hostname. 7. Apply connection, total-transfer, and response-size limits to reduce denial-of-service exposure. 8. Run fetching in a network-restricted sandbox that cannot reach internal management networks. 9. Apply equivalent controls to `scripts/fetch_rss.py` and the compatibility implementation. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unpinned third-party dependencies make installation non-reproducible<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-6`; related installation command in `README.md:25-28`; permissive dependency in `app/pyproject.toml:11` **Vulnerability Type**: Unpinned software supply-chain dependencies **Risk Level**: Low ### Vulnerable Code ```text feedparser trafilatura pyyaml pydantic openai pytest ``` The documented installation executes dependency resolution at installation time: ```bash python3 -m venv venv source venv/bin/activate pip install -r requirements.txt ``` The application package also permits a broad version range: ```toml dependencies = ["openai>=1.0.0"] ``` ### Technical Analysis The dependency manifest does not pin exact reviewed versions and does not provide package hashes. As a result, two installations performed at different times can resolve to materially different code. A compromised upstream release, malicious package takeover, or incompatible future version could therefore enter the environment without any repository change. `pytest` is also mixed into the main requirements despite being a development dependency, unnecessarily increasing the installation surface. No direct evidence of typosquatting or a currently malicious named package was found; the issue is the absence of reproducible dependency controls. ### Attack Path 1. A listed package account or release process is compromised, or a harmful version is published upstream. 2. An operator follows the documented `pip install -r requirements.txt` procedure. 3. Pip resolves the newest version satisfying the unconstrained or broad requirement. 4. Package installation hooks or imported runtime code execute with the privileges of the installing or pipeline user. 5. The compromised dependency can access the same files, environment credentials, and network resources available to RSS-Brew. ### Impact Assessment A malicious dependency can execute arbitrary Python code under the application user during installation or runtime. Dependin ...[truncated 344 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Generate a reviewed lock file with exact versions for all direct and transitive dependencies. 2. Use package hashes and install with `pip --require-hashes`. 3. Separate runtime dependencies from development and test dependencies. 4. Constrain package indexes to approved HTTPS repositories and disable unintended extra indexes. 5. Add automated vulnerability and provenance checks to dependency-update workflows. 6. Review dependency changes before updating the lock file. 7. Keep `requirements.txt` and `app/pyproject.toml` synchronized so both installation paths enforce equivalent constraints. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
app/src/rss_brew/cli.py:45
Finding
Documented dry-run mode still creates and commits persistent pipeline state<![CDATA[ ## Vulnerability Details **File Location**: `app/src/rss_brew/cli.py:45-52`; persistent operations in `scripts/run_pipeline_v2.py:217-266, 432-462`; contradictory documentation in `README.md:49-50` **Vulnerability Type**: Unsafe dry-run implementation and misleading operational boundary **Risk Level**: Low ### Vulnerable Code The CLI labels the operation as a dry run but only enables `--skip-core` and `--mock`: ```python def cmd_dry_run(ns: argparse.Namespace) -> int: script = LEGACY_SCRIPTS_ROOT / "run_pipeline_v2.py" argv = [ "--data-root", str(resolve_data_root(ns.data_root)), "--skip-core", "--mock", ] if ns.debug: argv.append("--debug") if ns.scoring_v2 or _env_scoring_v2_enabled(): argv.append("--scoring-v2") return _run_python_script(script, argv) ``` The orchestrator still writes a run manifest and staging data: ```python manifest: Dict[str, Any] = { "day": day, "run_id": run_id, "attempt": attempt, "started_at": now_iso(), "finished_at": None, "status": "running", "new_articles": 0, "deep_set_count": 0, "failure_reason": None, "delivery_status": "pending", "staging_path": str(staging_dir), "published_path": None, "finalize_started_at": None, "finalize_finished_at": None, "commit_token": None, "supersedes_run_id": None, "scoring_v2": True, } write_json(manifest_path, manifest) try: staging_dir.mkdir(parents=True, exist_ok=True) ``` It also publishes and commits the run: ```python daily_dir.mkdir(parents=True, exist_ok=True) with open(finalize_lock_path, "a+", encoding="utf-8") as lock_file: fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX) manifest = update_manifest( manifest_path, { "status": "finalize_in_progress", "finalize_started_at": now_iso(), "published_path": str(publish_dir), }, ) publish_staging_to_versioned( ...[truncated 2304 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a dedicated `--dry-run` or `--no-commit` option to the orchestrator. 2. In dry-run mode, direct all generated files to an automatically created temporary directory outside the production data root. 3. Suppress manifest creation, finalization locks, publication, winner selection, current-pointer changes, delivery-state changes, and deduplication-state updates. 4. Print or explicitly export preview artifacts only when the operator supplies an output path. 5. Add tests that snapshot the production data root before and after dry-run execution and assert that no files or metadata changed. 6. Until a true no-write mode exists, remove the “no writes” claim and clearly document every file and state transition produced by the command. ]]>
Vulnerability Patterns
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (97)

Tainted flow: 'req' from os.environ.get (line 59, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
last_body = ""
    for attempt in range(3):
        try:
            with request.urlopen(req, timeout=max(1.0, float(timeout or 20.0))) as resp:
                last_body = resp.read().decode("utf-8", errors="replace")
            break
        except error.HTTPError as exc:
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This code chunk is only a minimal package scaffold and version declaration. Its actual behavior is limited to exposing a version constant, which does not substantively match the declared purpose of running and operating an RSS digest pipeline. Because the claimed primary functionality is not represented in the supplied code, this is a material description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The code substantially matches the declared RSS-Brew CLI purpose for running the pipeline, performing dry-runs, inspecting the latest run, and updating delivery status. However, the description explicitly includes 'retry/finalize-aware operations,' and this code chunk does not expose any retry or finalize-related commands or logic. The extra scoring-v2 toggle is a supporting implementation detail rather than a material mismatch. Therefore this is a partial description-behavior mismatch due to overclaiming capabilities not present in the code.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description emphasizes operational control of the broader RSS-Brew digest pipeline, especially CLI usage for dry-runs, inspecting latest runs, updating delivery status, and retry/finalize-aware workflow handling. The supplied code does not implement those operator-facing lifecycle features. Instead, it is a core ingestion stage that fetches RSS feeds, filters by recency, deduplicates, extracts text, stores metadata/indexes, and writes run stats. While this is related to the RSS-Brew pipeline generally, the actual code’s primary purpose is narrower and materially different from the declared operational description. Therefore this is a description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description presents a broad operational skill for running and operating the RSS-Brew digest pipeline, including CLI operations, dry-runs, latest-run inspection, delivery status updates, and retry/finalize-aware behavior. The supplied code only implements digest composition and file output. It parses arguments for input JSON files, loads article sets and latest run stats, formats a markdown digest, and writes it to disk. While it partially aligns with 'latest-run inspection' by reading latest run stats, the primary behavior is much narrower than the declared purpose. Important declared capabilities—pipeline execution, dry-run behavior, delivery state changes, and retry/finalize handling—are absent. Therefore the description does not accurately represent what this code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description says this skill runs and operates an RSS-Brew digest pipeline with operational features such as CLI usage, dry-runs, latest-run inspection, delivery status updates, and retry/finalize-aware behavior. The supplied code does something materially different: it is a standalone compatibility script that requests arbitrary feed URLs over HTTP, parses RSS/Atom XML, extracts article metadata, and emits JSON. None of the claimed pipeline-management features are present, and the code introduces a distinct capability—external feed fetching/parsing—not reflected in the declared purpose. This is a clear description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description says this skill operates the RSS-Brew digest pipeline and related CLI/run-management tasks. However, this code specifically implements Phase A content scoring for articles using a DeepSeek model or mock heuristic. Its primary purpose is scoring input articles and writing scored results, not managing pipeline runs, inspecting latest runs, updating delivery status, or handling retry/finalize workflow operations. This is a material description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description presents this skill as a general operator for the RSS-Brew digest pipeline and associated run-management tasks. The supplied code does not implement those operational capabilities. Instead, it is a narrowly scoped Phase-B analyzer that processes scored articles, chooses a deep-analysis subset, invokes a model to produce summaries/category/deep analysis, and writes JSON plus markdown outputs. While this may be part of the broader RSS-Brew pipeline, the description materially overstates and misrepresents the actual behavior of this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description suggests a general operational skill for running and managing the RSS-Brew digest pipeline, including administrative/inspection actions like dry-runs, latest-run inspection, delivery status updates, and retry/finalize-aware behavior. The supplied code does not implement those management functions. Instead, it is a narrowly scoped phase processor that reads scored articles, ranks them, applies selection guardrails, partitions them into deep and other sets, and writes ranking/distribution JSON artifacts. This is a materially different primary purpose from the declared operational pipeline control description, so it should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description is about running and operating the RSS-Brew digest pipeline, including operational CLI behaviors like dry-runs, inspecting latest runs, updating delivery status, and retry/finalize-aware actions. The supplied code does none of those things. Instead, it is a standalone rendering utility that reads a markdown digest file, parses article sections, generates HTML, writes output files, and calls WeasyPrint to produce a PDF. This is a materially different primary purpose from pipeline operations, so the description does not accurately represent the code's behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description says the skill runs and operates the RSS-Brew digest pipeline with CLI operations such as dry-runs, latest-run inspection, delivery status updates, and retry/finalize-aware workflow handling. The supplied code does not implement or operate such a pipeline. Instead, it is a test file focused on a separate Phase A scoring component: loading a scoring script, parsing wrapped JSON score output, clamping scores, retrying transient API failures, and validating output schema/order for scored articles. These behaviors are materially different from the declared operational pipeline purpose, so this is a clear mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description is about operating the RSS-Brew digest pipeline and app CLI features such as dry-runs, latest-run inspection, delivery status updates, and retry/finalize-aware operations. The supplied code does not implement or exercise those capabilities. Instead, it is a unit/integration test for a separate analysis script, specifically validating that a '--preselected' flag causes phase_b_analyze.py to skip internal selection logic while producing expected output. This is a materially different primary purpose from the declared operational CLI behavior, so it should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description says the skill runs and operates the RSS-Brew digest pipeline with operational actions such as app CLI usage, dry-runs, latest-run inspection, delivery status updates, and retry/finalize-aware behavior. The supplied code chunk does not implement or invoke those pipeline operations. Instead, it is a test file focused on a separate `phase_model_score.py` component that scores articles, builds prompts, parses structured scoring responses, and preserves backward-compatible output fields. This is a materially different purpose from the declared operational pipeline management behavior, so the description does not accurately represent the code.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description says the skill runs and operates the RSS-Brew digest pipeline through app CLI functions such as dry-runs, latest-run inspection, delivery status updates, and retry/finalize-aware operations. The supplied code chunk does something materially different: it is a test file for a specific ranking/distribution script. It constructs JSON inputs, patches sys.argv, invokes the phase_rank_distribute main function, and asserts expected outputs and guardrails. While this may be related to the broader RSS-Brew system, the code’s actual purpose is validating a ranking/distribution phase, not operating the pipeline or managing delivery/run lifecycle functions. That is a substantive description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description says this skill runs and operates an RSS-Brew digest pipeline and related CLI operational tasks. However, the actual code chunk is not pipeline-operations code; it is a unit/integration test file validating a specific content-processing phase that scores and filters articles. It manipulates temporary JSON files, monkeypatches sys.argv, calls a script's main(), and checks rejection/fallback semantics. None of the described operational features—dry runs, latest-run inspection, delivery status updates, retry/finalize handling—appear in this code. This is a materially different primary purpose, so it should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared purpose describes operational pipeline/CLI functionality for running and managing the RSS-Brew digest pipeline. The actual code chunk does not implement or exercise pipeline operations, CLI usage, delivery updates, retry/finalize behavior, or latest-run inspection. Instead, it is a parser unit test focused on extracting structured data from a markdown digest file. This is a materially different purpose from the declared operational skill behavior, so it should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This code does not implement or expose the declared operational pipeline functionality. Instead, it contains tests for helper functions rank_key and select_winner. While these helpers may support finalize-aware pipeline behavior indirectly, the actual chunk’s primary purpose is test verification of winner-selection ordering logic, not operating the RSS-Brew digest pipeline or handling CLI, delivery updates, retries, or run inspection. Therefore the description materially overstates and misrepresents what this code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The code chunk is narrowly focused on RSS feed ingestion and article extraction, not on operating the broader digest pipeline described. It parses a few file-path and lookback CLI arguments, but those are for the core fetch/extract job only. There is no implementation of dry-run behavior, inspection of prior/latest runs, delivery status management, retry/finalize workflow handling, or app-level operational commands. The primary behavior is feed fetching, text extraction, deduplication, metadata normalization, and writing output/run-stats files. Therefore the declared description materially overstates and mischaracterizes what this code actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The code chunk is a digest writer only. It parses CLI arguments, loads JSON inputs, fetches latest run stats, formats article summaries and pipeline stats into markdown, and writes the result to a file. The declared description describes a much broader operational skill for the RSS-Brew digest pipeline, including app CLI usage, dry-runs, latest-run inspection, delivery status updates, and retry/finalize-aware behavior. None of those operational capabilities are present here except a limited use of latest run stats as input. This is a material description-to-behavior mismatch due to substantial missing declared functionality and a narrower actual purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description says this skill runs and operates an RSS-Brew digest pipeline with CLI workflow features such as dry-runs, latest-run inspection, delivery status updates, and retry/finalize-aware behavior. The supplied code does none of that. Instead, it simply accepts URLs as command-line arguments, downloads feed XML over HTTP, parses Atom or RSS items, and emits article metadata as JSON. This is a materially different primary purpose and introduces undeclared network-fetching/feed-parsing behavior while omitting the described pipeline-management functionality.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description is about operating the RSS-Brew digest pipeline and handling CLI workflow operations like dry-runs, run inspection, delivery status updates, and retry/finalize logic. The code instead performs a specific content-scoring task for articles in Phase A, including building prompts, calling an external DeepSeek model API, parsing JSON responses, and outputting scored articles. That is a materially different primary purpose from the declared operational pipeline management behavior, so this is a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description is about operating the RSS-Brew digest pipeline at an application/CLI level, with operational features such as dry-runs, inspecting latest runs, updating delivery status, and retry/finalize-aware execution. The supplied code instead is a specific pipeline stage implementation for Phase B analysis. It reads scored article JSON, selects a subset of articles, prompts an LLM for category and summaries, optionally includes deep analysis for high-scoring articles, writes markdown files, and emits analyzed JSON. While it is related to RSS-Brew, its primary purpose is content analysis/generation, not general pipeline operation or delivery management. The operational capabilities named in the description are absent from this code chunk, so the description does not accurately represent the behavior shown.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description says this skill is for running and operating the RSS-Brew digest pipeline, with capabilities like app CLI usage, dry-runs, latest-run inspection, delivery status updates, and retry/finalize-aware operations. The supplied code instead implements a specific enrichment phase: it loads an input JSON file, searches the web for each article title via Tavily (or generates mock results), attaches enrichment data to each article, writes the enriched output, and prints enrichment statistics. This is a materially different primary purpose from operational pipeline control/status management, and it uses an undeclared external search capability. Therefore the description does not accurately represent the code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description suggests a general pipeline operations skill for running the RSS-Brew digest system, inspecting runs, updating delivery status, and handling retries/finalization. The supplied code does none of those operational tasks. Instead, it is narrowly focused on scoring articles in Phase C using a structured rubric and an external model API. This is a materially different primary purpose and includes undeclared capabilities such as external API use and content scoring.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description presents a general-purpose operational skill for running and managing the RSS-Brew digest pipeline, including execution-management features like dry-runs, latest-run inspection, delivery status updates, and retry/finalize handling. The supplied code does not provide those capabilities. Instead, it is a narrowly scoped transformation script for ranking articles and distributing them into deep/other sets, with guardrails such as source caps, topic caps, confidence blocking, and source eligibility filtering from a YAML config. While it is CLI-based and plausibly part of the pipeline, its actual behavior is much narrower and materially different from the declared operational management functions.

Static analysis

No suspicious patterns detected.