Back to skill

Security audit

iran-finance-markets-monitor

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed Iranian market data collector and report generator; its network access and local JSON output fit that purpose, with some dependency and scoping hygiene to consider.

Install this only if you want a Python-based live market watcher that contacts public market/news sites and may write dated JSON snapshots locally. Prefer running with --stdout-only first, and consider pinning dependencies or using a locked environment before routine use.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (16)

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · scripts/iran_market_watcher.py (reported line 221)May include surrounding context.

python
ted_price(data, "iran_fx_gold", field, price, f"TGJU table {index}")
        if len(tables) > 33:
            mids = []
            for row in tables[33].find_all("tr"):
                cells = [cell.get_text(" ", strip=True) for cell in row.find_all(["td", "th"])]
                if len(cells) >= 4 and normalize_digits(cells[0]).strip() in {"نوبیتکس", "والکس", "بیت پین", "بیت‌پین"}:
                    buy, sell = parse_number(cells[1]), parse_number(cells[2])
                    if buy and sell and abs(buy - sell) / ((buy + sell) / 2) <= 0.005:
                        mids.append((buy + sell) / 2 / 10)
            if mids:
                spread = (max(mids) - min(mids)) / statistics.mean(mids)
                if spread <= 0.005:
                    set_validated_price(data, "crypto", "usdt_toman", round(statistics.mean(mids)), "TGJU table 33 exchange median")
                else:
                    data["errors"].append({"source": "TGJU table 33", "type":

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill explicitly instructs the agent to install dependencies, run Python code, use network access for live collection, and write output artifacts, but it does not declare any tool scope or permission boundaries in the manifest. That mismatch can cause an orchestrator to invoke a skill with broader capabilities than a reviewer or policy engine can easily assess, increasing the risk of unintended network access, file writes, or environment interaction.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The description is very broad and includes many generic finance-related verbs like monitor, collect, validate, compare, summarize, and report, which can cause the skill to be selected for a wide range of ordinary market questions. Because this skill may trigger code execution, network retrieval, and file output, overbroad routing increases the chance of unnecessary capability use and accidental invocation in contexts where a simpler, non-executing response would be safer.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/iran_market_watcher.py (reported line 171)May include surrounding context.

python
data = empty_snapshot(timestamp)
    try:
        params = {"ids": "bitcoin,ethereum,tether,solana,binancecoin,ripple", "vs_currencies": "usd", "include_24hr_change": "true", "include_24hr_vol": "true"}
        response = requests.get("https://api.coingecko.com/api/v3/simple/price", params=params, headers={"User-Agent": USER_AGENT}, timeout=15) if requests else None
        if response is None:
            raise RuntimeError("requests is required")
        response.raise_for_status()

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/iran_market_watcher.py (reported line 185)May include surrounding context.

python
data = empty_snapshot(timestamp)
    try:
        params = {"ids": "bitcoin,ethereum,tether,solana,binancecoin,ripple", "vs_currencies": "usd", "include_24hr_change": "true", "include_24hr_vol": "true"}
        response = requests.get("https://api.coingecko.com/api/v3/simple/price", params=params, headers={"User-Agent": USER_AGENT}, timeout=15) if requests else None
        if response is None:
            raise RuntimeError("requests is required")
        response.raise_for_status()

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/iran_market_watcher.py (reported line 194)May include surrounding context.

python
except Exception as exc:
        data["errors"].append({"source": "CoinGecko /global", "type": "network", "detail": str(exc)})
    try:
        response = requests.get("https://api.alternative.me/fng/", timeout=15) if requests else None
        if response is None:
            raise RuntimeError("requests is required")
        response.raise_for_status()

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The manifest centers on Iranian financial markets and specific market indicators/sources, including Persian market reporting. Falling back to Cointelegraph RSS introduces a broader, non-Iran-specific news feed that is not clearly implied by the stated scope.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes collection, validation, comparison, summarization, and reporting of Iranian financial markets, which implies data retrieval and presentation. In main, the script creates directories and writes dated JSON snapshots to disk unless --stdout-only is used, adding stateful local persistence beyond the manifest's stated behavior.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
89% confidence
Finding

The dependency is specified with only a minimum version, which allows future builds to resolve to different releases over time. This creates supply-chain uncertainty and can introduce breaking or vulnerable versions without review, though no specific exploit is demonstrated by this line alone.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
jdatetime>=5.2
requests>=2.31
beautifulsoup4>=4.12
feedparser>=6.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

Using requests>=2.31 permits installation of any later version, making builds non-reproducible and preventing assurance about whether a vulnerable or fixed release is deployed. In a market-monitoring skill that performs external HTTP requests, this matters more because network-facing libraries are directly exposed to attacker-controlled URLs, redirects, and credential-handling behaviors.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
jdatetime>=5.2
requests>=2.31
beautifulsoup4>=4.12
feedparser>=6.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
93% confidence
Finding

The manifest does not pin requests, and that package has multiple known advisories across versions, so the security posture of the deployed environment cannot be verified. Given this skill likely performs outbound web requests to collect financial data, a vulnerable requests release could expose credentials, weaken TLS-related assumptions, or mishandle malicious URLs.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
88% confidence
Finding

An unpinned beautifulsoup4 dependency allows uncontrolled upgrades and non-reproducible environments. While this is primarily a supply-chain hygiene issue rather than an immediate exploit, parser libraries process untrusted remote content and should be tightly versioned.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
jdatetime>=5.2
requests>=2.31
beautifulsoup4>=4.12
feedparser>=6.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

feedparser>=6.0 allows any newer release, so the deployed version may vary and may include known or newly introduced security issues. Because this skill ingests remote feeds and market data, an unsafe parser version could increase risk when processing attacker-influenced content.

Content

Scanner excerpt · requirements.txt (reported line 4)May include surrounding context.

text
jdatetime>=5.2
requests>=2.31
beautifulsoup4>=4.12
feedparser>=6.0

Unverifiable Dependency: feedparser has 10 known advisory(ies) (CVE-2011-1157 (feedparser Cross-site Scripting vulnerability); CVE-2009-5065 (feedparser Cross-site Scripting vulnerability); CVE-2011-1158 (feedparser Cross-site Scripting vulnerability) +7 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
91% confidence
Finding

Because feedparser is unpinned and has known historical advisories, it is impossible to determine from this manifest whether a safe or vulnerable version will be installed. This is more concerning in a skill that consumes external feeds, since parser flaws can be triggered by crafted remote content and may affect downstream rendering or data handling.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/iran_market_watcher.py (reported line 272)May include surrounding context.

python
parser.add_argument("--stdout-only", action="store_true", help="Print JSON without writing a snapshot")
    parser.add_argument("--log-level", default="WARNING", choices=("DEBUG", "INFO", "WARNING", "ERROR"))
    args = parser.parse_args()
    logging.basicConfig(level=getattr(logging, args.log_level), format="%(levelname)s %(message)s")
    snapshot = fetch_market_data()
    if not args.stdout_only:
        output_dir = Path(args.output_dir)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The entire template is fixed in Persian and explicitly uses Tehran local time, which constitutes a language/locale constraint in natural-language content. The file does not indicate that this locale is optional, user-selected, or justified as a region-specific skill.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_watcher.py:9