Back to skill

Security audit

Iran Intelligence Radar (Persian X Monitor)

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly transparent about Iran-related X monitoring, billing, and alerts, but it needs Review because failed searches can silently produce realistic mock intelligence that may trigger charges and external alerts.

Review this before installing in any operational setting. Disable or strictly configure Telegram/channel alerts, confirm exactly what is sent to SkillPay, translation providers, and alert destinations, and do not treat reports as live intelligence until the mock fallback is removed or clearly marked and blocked from billing, persistence, and alerts. Billing should also use provider-side idempotency or transactional state before real users are charged.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
skills/persian_x_radar/search.py:119
Finding
Fabricated fallback data can trigger operational intelligence alerts<![CDATA[ ## Vulnerability Details **File Location**: `skills/persian_x_radar/search.py:119-160`; downstream alert processing occurs at `skills/persian_x_radar/agent.py:156-160` and `skills/persian_x_radar/agent.py:205-211` **Vulnerability Type**: Failure handling with unsafe production mock data **Risk Level**: High ### Vulnerable Code ```python def search_with_fallback( req: SearchRequest, x_keyword_search: Optional[ToolFn] = None, x_semantic_search: Optional[ToolFn] = None, web_search: Optional[ToolFn] = None, ) -> List[RawTweet]: query = build_x_query(req) tool_order = [ ("x_keyword_search", x_keyword_search), ("x_semantic_search", x_semantic_search), ("web_search", web_search), ] for _, tool_fn in tool_order: if tool_fn is None: continue try: rows = tool_fn(query=query) if rows: return _normalize_tool_rows(rows) except Exception: continue now = datetime.now(timezone.utc) # Deterministic local mock data to keep the skill runnable without external tools. mock = [ RawTweet( id="m1", author="@analyst_fa", timestamp=now - timedelta(hours=2), text="بحث درباره حمله و موشک در حال افزایش است", likes=420, retweets=130, replies=12, url="https://x.com/analyst_fa/status/1", ), RawTweet( id="m2", author="@iran_watch", timestamp=now - timedelta(hours=3), text="گزارش هایی از اعتراض در چند شهر منتشر شده است", likes=170, retweets=42, replies=9, url="https://x.com/iran_watch/status/2", ), ] return mock ``` The returned rows are subsequently processed and dispatched as ordinary intelligence: ```python tweets = search_with_fallback( req=req, x_keyword_search=self.tools.x_keyword_sea ...[truncated 2397 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove implicit mock records from the production search path. 2. Return an explicit status such as `search_unavailable`, including sanitized provider failure information. 3. Distinguish between: - A successful search with zero results. - Missing search tools. - Provider errors or timeouts. 4. Permit mock data only when an explicit test or development flag is enabled. 5. Add an immutable `is_mock` or `source_type` attribute to simulated records. 6. Block alert dispatch, billing, trend-state updates, escalation history, and daily-history writes whenever results are simulated. 7. Replace broad `except Exception` handling with specific exception handling and structured logging. 8. Add integration tests confirming that provider failure cannot produce a successful live-intelligence report or external alert. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
skills/persian_x_radar/agent.py:100
Finding
Race condition can cause duplicate billing and cooldown-state corruption<![CDATA[ ## Vulnerability Details **File Location**: `skills/persian_x_radar/agent.py:100-114`; local state implementation at `skills/persian_x_radar/cache.py:13-52` **Vulnerability Type**: Non-atomic check-then-charge operation and unsafe concurrent state updates **Risk Level**: Medium ### Vulnerable Code ```python def _billing_gate(self, user_id: str) -> Dict[str, Any]: billing_cfg = self.config.get("billing", {}) cooldown_minutes = int(billing_cfg.get("charge_cooldown_minutes", 15)) skill_id = str(billing_cfg.get("skill_id", "")) price = float(billing_cfg.get("price_per_call", 0.0)) if has_recent_charge(user_id, cooldown_minutes): self.logger.info("charge skipped (recent payment) user_id=%s price=$%.2f", user_id, price) return {"allowed": True, "billing_state": "recent_payment", "price": price} charge_result = charge_user(user_id=user_id) if charge_result.get("success"): record_charge(user_id) self.logger.info( "User charged $%.2f for Persian X Radar scan user_id=%s skill_id=%s", price, user_id, skill_id, ) ``` The cache uses an unsynchronized read-modify-write sequence: ```python def has_recent_charge(user_id: str, cooldown_minutes: int) -> bool: last_ts = get_last_charge_timestamp(user_id) if last_ts is None: return False now = datetime.now(timezone.utc) if last_ts.tzinfo is None: last_ts = last_ts.replace(tzinfo=timezone.utc) return now - last_ts <= timedelta(minutes=cooldown_minutes) def record_charge(user_id: str) -> None: cache = _read_cache() cache[user_id] = datetime.now(timezone.utc).isoformat() _write_cache(cache) ``` ```python def _write_cache(cache: Dict[str, str]) -> None: with CACHE_FILE.open("w", encoding="utf-8") as f: json.dump(cache, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis Cooldown verification, remote charging, and charge recording are ...[truncated 1808 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use a provider-supported idempotency key derived from the user, skill, and cooldown window. 2. Move cooldown enforcement into a transactional datastore with an atomic conditional insert or update. 3. Lock the complete check, charge, and state-update sequence per user when local coordination is unavoidable. 4. Do not rely on a package-local JSON file in multi-process or multi-host deployments. 5. If file storage must remain: - Use an inter-process file lock. - Write to a temporary file in the same directory. - Flush and synchronize it. - Atomically replace the destination. - Apply restrictive file permissions. 6. Preserve and recover malformed state rather than silently interpreting corruption as an empty cache. 7. Reconcile local records with provider transaction identifiers. 8. Add concurrency tests that issue simultaneous requests and verify that only one charge occurs. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unpinned and unnecessary dependencies create supply-chain exposure<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-3` **Vulnerability Type**: Non-reproducible dependency resolution **Risk Level**: Low ### Vulnerable Code ```text pyyaml requests python-dateutil ``` ### Technical Analysis The dependency declarations do not constrain versions or verify package hashes. Every installation may therefore resolve different package releases depending on installation time and package-index state. This prevents deterministic review of the code that will be installed. A compromised future release, unexpected incompatible release, or dependency-resolution change could enter the environment without any project modification. The inspected implementation directly imports PyYAML, while `requests` and `python-dateutil` do not appear necessary for the reviewed code paths, increasing attack surface without an identified functional requirement. No evidence was found that these package names are typosquatted or currently malicious. The finding concerns unsafe dependency management rather than a confirmed malicious package. ### Attack Path 1. A deployment runs `pip install -r requirements.txt`. 2. The package installer resolves the latest versions allowed by the unconstrained declarations. 3. A future compromised, vulnerable, or incompatible release is selected. 4. Package installation or later imports execute code that was not part of the audited dependency set. 5. The resulting deployment differs from the reviewed build and may expose the host or application data. ### Impact Assessment The exact impact depends on the behavior of a subsequently resolved package release. Python packages installed into the application environment can generally execute with the privileges of the installer or application process. Potential scope therefore includes: - Application code execution. - Access to environment variables and application-readable files. - Network access available to the process. - Service disruption through inc ...[truncated 175 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `requests` and `python-dateutil` if they are not required by supported runtime paths. 2. Pin every direct dependency to an exact reviewed version. 3. Generate and commit a lock file containing resolved transitive dependencies. 4. Require cryptographic hashes during installation, such as with a hash-locked requirements file. 5. Install only from approved indexes over authenticated TLS. 6. Run dependency vulnerability and license scanning in continuous integration. 7. Use automated dependency updates that require review and testing before merge. 8. Build releases in an isolated environment and retain a software bill of materials for each artifact. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (33)

Credential Access

High
Category
Privilege Escalation
Content
__pycache__/
*.pyc
logs/
.env
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Hidden Instructions

High
Category
Prompt Injection
Content
# System Prompt: Persian X Radar OSINT Intelligence Radar

You are an OSINT intelligence radar focused on high-signal Persian content from X (Twitter) related to Iran.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
# System Prompt: Persian X Radar OSINT Intelligence Radar

You are an OSINT intelligence radar focused on high-signal Persian content from X (Twitter) related to Iran.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
# System Prompt: Persian X Radar OSINT Intelligence Radar

You are an OSINT intelligence radar focused on high-signal Persian content from X (Twitter) related to Iran.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The README states that the skill sends operational and Telegram alerts but does not clearly warn users that analyzed content may be transmitted to an external messaging service. In an OSINT/intelligence context, this can expose sensitive query results, monitored subjects, or user activity to third-party systems without informed consent.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The skill description says content is translated to English, Arabic, and Chinese as a fixed behavior, without indicating that users can choose languages or opt out. Forced translation can create unnecessary disclosure of monitored content into additional representations and may violate user expectations or policy constraints in intelligence workflows.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill advertises automatic Telegram alert dispatch and channel hooks, which implies external transmission of collected content or derived intelligence to a third-party service. Because the description does not clearly state what data is sent, when it is sent, and whether this requires explicit user opt-in, users may unknowingly exfiltrate monitored content, metadata, or sensitive analysis outputs outside the local agent environment.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The prompt instructs the skill to always use `lang:fa`, which imposes a specific language scope by default. Elsewhere it also requires translation/output in fixed languages, but does not offer the user a language or locale choice or document this as an opt-in regional constraint.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The instructions require translation to English, Arabic, and Chinese, which enforces specific language outputs regardless of user preference. This is a natural-language policy concern because no opt-in, selection mechanism, or documented justification is provided for these locale choices.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The markdown requires the report to always include English and Chinese summaries, imposing fixed locale behavior. Because the skill does not offer language selection or explain why these summaries are mandatory, this violates the language/locale policy guidance.

Ae4

Medium
Category
analysis-evasion
Confidence
94% confidence
Finding
The first line contains a suspicious hidden Unicode character, most likely a UTF-8 BOM before `pyyaml`. Hidden or non-printing characters in dependency manifests can cause parsing inconsistencies across tools, make reviews less reliable, and in some cases be abused to disguise dependency names or alter interpretation.

Context-Inappropriate Capability

Medium
Confidence
85% confidence
Finding
The core code behavior appears to be scanning Persian-language X/Twitter content, translating it, ranking results, and generating alerts/reports. In addition to that monitoring functionality, the skill enforces per-user charging, checks balances, and constructs external payment links, which is a distinct monetization capability not implied by the scan/reporting logic itself.

Context-Inappropriate Capability

Medium
Confidence
81% confidence
Finding
The file presents itself through names and command parsing as a 'Persian X Radar' scanner/report generator, but it also sends Telegram alerts as a side effect of running a scan. Without a manifest or documentation declaring external messaging/notification behavior, this outbound communication capability is broader than the evident analytical purpose.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The bilingual summary function always returns English and Chinese text, and the main execution path prints a Chinese summary when present. This imposes a specific locale/language choice in user-facing output without offering a language preference or documenting why Chinese is required.

Natural-Language Policy Violations

Medium
Confidence
82% confidence
Finding
The natural-language alert text explicitly states it is monitoring 'Persian X', and the code is structured around Persian-language content via `text_fa`. There is no indication of user opt-in or configurable locale/language selection, which can violate language or locale policy requirements.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code sends a composed alert message to external channels via `send_alert_tool`, including `author` and `link` fields from each row. The file contains no confirmation prompt, logging/print statement, or comment/docstring warning that data will be transmitted to alert channels.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The charge_user function sends user_id, skill_id, and amount to an external billing endpoint via _request_json. In this file there is no confirmation prompt, print/log disclosure, or explanatory comment/docstring warning that calling this function initiates a remote billing action affecting user data and charges.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding
Suspicious Unicode normalization or mixed-script content

Vague Triggers

Medium
Confidence
89% confidence
Finding
This manifest describes the skill in broad terms as an 'OSINT Intelligence Radar for Persian-language X content related to Iran' that detects trends, translates, and sends alerts, but it does not define clear trigger phrases, invocation boundaries, or exclusion conditions. In a manifest file, this kind of open-ended description can make it unclear when the skill should activate versus when it should not.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The translation configuration hard-codes destination languages to English, Arabic, and Chinese. This is a natural-language policy concern because the skill imposes specific output locales without indicating user choice, opt-in, or a documented justification for the forced language set.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file generates output with a mandatory "AI Summary (Chinese)" section and returns a `chinese_summary` field, but there is no indication of user opt-in, locale selection, or region-specific justification. This creates a natural-language locale policy issue because the skill imposes a specific language in its output rather than offering a choice.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The search query is forced to `lang:fa`, which imposes a specific language/locale constraint in code. The file does not show any user choice, opt-in mechanism, or documented region-specific justification for limiting results to Persian content.

External Transmission

Medium
Category
Data Exfiltration
Content
logger.warning("telegram alert skipped due to missing bot_token/chat_id")
        return False

    url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
    payload = {
        "chat_id": chat_id,
        "text": _build_message(escalation, trending, rows),
Confidence
90% confidence
Finding
The function transmits monitored content, including escalation details and example links, to an external third-party service (Telegram) based solely on configuration. In this skill context, the data appears operationally sensitive, and sending it to Telegram can expose intelligence, metadata, or internal monitoring results to an external platform if enabled unintentionally or used in an environment with stricter handling requirements.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code performs an outbound HTTP request to Telegram and includes generated alert text plus example links derived from `rows`, which may transmit user or system-derived monitoring data off-platform. While failures and success are logged, there is no user-facing warning, confirmation, or explanatory comment/docstring disclosing that this skill sends collected data to a third-party service.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This code passes the input text to an injected translation tool, which could perform a network/API call and transmit user-provided content externally. There is no confirmation prompt, logging, comment, or docstring in this file warning that text may be sent to another service.

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
prompts/system_prompt.md:1