Back to skill

Security audit

airoom-finance

Security checks for vulnerabilities and agentic risk

Overview

The skill is mainly a financial-data downloader, but its documentation and implementation create Review-level concerns around autonomous financial use, credential handling, and unsafe downloads.

Install only if you are comfortable reviewing financial outputs manually, using it as informational data only, avoiding autonomous trading or account delegation, avoiding WordPress credentials unless HTTPS is enforced, and treating all downloaded files as untrusted.

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

Error
Location
main.py:81
Finding
WordPress credentials may be transmitted over plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `main.py:81-84, 288-300, 337-350`; related defaults in `config.json:2-9`, `SKILL.md:556-579`, and `README.md:559-573` **Vulnerability Type**: Plaintext transmission of authentication credentials **Risk Level**: High ### Vulnerable Code ```python # Set default values for airoom.ltd financial data platform if "wordpress" not in config: config["wordpress"] = { "url": "http://airoom.ltd", "username": "", "password": "" } if "target" not in config: config["target"] = { "page_url": "http://airoom.ltd/index.php/airoom/" } ``` When authentication is required, the same configurable base URL is used to construct the login endpoint: ```python if requires_login and username and password: print("\n[Step 2] Logging into WordPress...") login_url = f"{base_url}/wp-login.php" try: page.goto(login_url, wait_until="domcontentloaded", timeout=30000) print("Entering login credentials...") page.fill("#user_login", username) page.fill("#user_pass", password) page.click("#wp-submit") ``` The shipped configuration also uses plaintext HTTP: ```json { "wordpress": { "url": "http://airoom.ltd", "username": "", "password": "" }, "target": { "page_url": "http://airoom.ltd/index.php/airoom/" } } ``` ### Technical Analysis The downloader supports optional WordPress authentication, but neither configuration validation nor login handling requires HTTPS. The default `WP_URL` uses `http://`, and the login endpoint is created by appending `/wp-login.php` to that value. Although the documented target page is public, authenticated pages are explicitly supported. Consequently, a user who configures a username and password can cause the Skill to submit those credentials over an unencrypted HTTP connection. Host equality checks do not provide transport confidentiality or server authentication. They do not prevent int ...[truncated 1212 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `https` whenever credentials are present: ```python parsed_base = urlparse(base_url) if username or password: if parsed_base.scheme.lower() != "https": raise ValueError("HTTPS is required when WordPress credentials are configured") ``` 2. Prefer requiring HTTPS for all network access, including public downloads. 3. Reject redirects from HTTPS to HTTP and verify the final URL after every navigation. 4. Remove plaintext HTTP defaults from `main.py`, `config.json`, `SKILL.md`, and `README.md`. 5. Do not submit credentials when the login origin differs from the explicitly approved origin. 6. Consider removing authenticated-page support entirely because the declared default functionality only needs a public page. 7. Encourage dedicated, least-privileged WordPress accounts when authentication is unavoidable. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
main.py:288
Finding
Extracted download links can navigate to untrusted external origins<![CDATA[ ## Vulnerability Details **File Location**: `main.py:288-300, 388-443, 495-514` **Vulnerability Type**: Incomplete destination validation and unrestricted outbound navigation **Risk Level**: Medium ### Vulnerable Code The code validates only the initially configured page: ```python # Validate URL is from expected domain for security if base_url and page_url: parsed_base = urlparse(base_url) parsed_page = urlparse(page_url) # Ensure target URL is on the same domain as base URL if parsed_base.netloc and parsed_page.netloc: if parsed_base.netloc != parsed_page.netloc: print("Security Error: Target URL must be on the same domain as the WordPress URL") return False ``` Links are then extracted from the page: ```python href = link.get_attribute("href") if href and is_downloadable_link(href, link.inner_text()) \ and not any(l["href"] == href for l in file_links): text = link.inner_text().strip() or link.get_attribute("title") or "" file_type = detect_file_type(href, text) file_links.append({ "href": href, "text": text, "type": file_type }) ``` Each extracted URL is subsequently visited without applying the same origin validation: ```python for i, file_info in enumerate(files_to_download): href = file_info["href"] file_type = file_info["type"] filename = href.split('/')[-1] if is_file_extension_blocked(filename): continue try: with page.expect_download(timeout=60000) as download_info: page.goto(href, wait_until="domcontentloaded", timeout=30000) ``` ### Technical Analysis The initial `WP_TARGET_URL` must have the same `netloc` as `WP_URL`, but this restriction is not applied to links discovered within the page. A page controlled or compromised by an attacker can contain an absolute link to an unrelated origin. If it appears downloadable, the Skill passes it directly to `page.goto()`. This contradicts the d ...[truncated 1652 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Normalize every extracted URL with `urljoin(page_url, href)`. 2. Validate each normalized destination before navigation. 3. Require an explicit scheme allowlist, preferably only `https`. 4. Compare normalized hostnames and effective ports against a strict destination allowlist. 5. Reject user-info components, unexpected ports, malformed URLs, and non-HTTP schemes. 6. Validate every redirect target and reject cross-origin redirects. 7. Use a direct HTTP download client with redirects disabled or tightly constrained instead of full browser navigation where possible. 8. Update documentation to accurately describe all possible outbound connections. 9. Add automated tests covering absolute external links, protocol-relative URLs, redirects, alternate ports, and hostname normalization edge cases. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
main.py:451
Finding
Declared file-type allowlist is not enforced for downloaded content<![CDATA[ ## Vulnerability Details **File Location**: `main.py:32-39, 231-264, 451-464, 495-527` **Vulnerability Type**: Insufficient validation of downloaded file types and filenames **Risk Level**: Medium ### Vulnerable Code The implementation declares an allowlist: ```python ALLOWED_EXTENSIONS = [ '.csv', '.txt', '.xlsx', '.xls', '.doc', '.docx', '.pdf', '.zip', '.rar', '.7z', '.json', '.xml', '.png', '.jpg', '.jpeg', '.gif', '.bmp', '.svg', '.webp', '.ico', '.mp3', '.wav', '.ogg', '.flac', '.mp4', '.avi', '.mkv', '.mov', '.webm', '.html', '.htm', '.css' ] ``` However, arbitrary links can be classified as downloadable solely from their visible text: ```python # Check text for download keywords text_lower = text.lower() download_keywords = [ 'download', '下载', 'file', '文件', 'attachment', '附件', '数据', 'data' ] if any(keyword in text_lower for keyword in download_keywords): return True ``` The final filter checks only a limited blocklist: ```python for file_info in file_links: filename = file_info["href"].split('/')[-1] if is_file_extension_blocked(filename): blocked_count += 1 print(f" [BLOCKED] {filename} - dangerous file type") else: safe_file_links.append(file_info) ``` The same blocklist-only check is repeated before navigation: ```python filename = href.split('/')[-1] if is_file_extension_blocked(filename): print(f"\nSkipping {i+1}: {filename} - blocked for security") continue ``` Finally, the server-provided filename is trusted for saving: ```python original_name = download.suggested_filename if not original_name or original_name == "unknown": original_name = href.split('/')[-1] if '?' in original_name: original_name = original_name.split('?')[0] save_path = output_dir / original_name download.save_as(str(save_path)) ``` ### Technical Analysis Despite the comments and documentation claiming that only safe types are downloaded, the code does not req ...[truncated 1970 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a minimal allowlist appropriate to financial data, such as CSV and carefully parsed JSON. 2. Validate the final `download.suggested_filename`, not only the link URL. 3. Apply `Path(filename).name` and reject path separators, control characters, reserved names, and suspicious Unicode. 4. Require agreement among: - URL path extension, - final filename extension, - response `Content-Type`, - file signature or magic bytes. 5. Reject unknown formats rather than allowing everything not present in the blocklist. 6. Remove HTML, SVG, legacy Office formats, and executable-capable archives unless strictly required. 7. If archives are necessary, inspect their entries, reject executable or traversal paths, cap decompressed size, and never extract automatically. 8. Apply per-file and aggregate size limits. 9. Save files in a non-executable, isolated directory and prevent overwriting existing files. 10. Scan downloaded content before exposing it to users or downstream Agent context. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Mutable dependency versions and unverified browser installation create supply-chain exposure<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-2`; related installation commands in `_meta.json:6-10` and `SKILL.md:540-548` **Vulnerability Type**: Unpinned third-party dependencies and non-reproducible installation **Risk Level**: Low ### Vulnerable Code ```text playwright>=1.40.0 requests>=2.31.0 ``` The metadata instructs installation directly from these mutable requirements and then downloads a browser component: ```json "installation": { "type": "python-package", "requirements": [ "pip install -r requirements.txt", "playwright install chromium" ], "description": "Install Python dependencies and Chromium browser for web automation" } ``` ### Technical Analysis The lower-bound-only constraints permit any future version of Playwright, Requests, and their transitive dependencies. There is no lockfile or integrity hash to make installation reproducible. The separate `playwright install chromium` command also downloads and installs a browser artifact without a project-level integrity manifest. Browser automation is necessary for the current implementation, but accepting mutable package and browser versions exceeds the minimum supply-chain trust required for a reproducible Skill release. The audited `main.py` does not import or use `requests`, so that dependency unnecessarily increases the installation and vulnerability surface. No evidence was found that either named package is intentionally malicious or typosquatted. The confirmed issue is unsafe dependency management rather than a known malicious dependency. ### Attack Path 1. A user installs the Skill at a later date. 2. `pip` resolves versions newer than those originally reviewed. 3. Installation executes package build or installation behavior and installs mutable transitive dependencies. 4. Playwright downloads a compatible Chromium artifact. 5. A compromised future release, dependency account, package index path, build artifact, or browser distribution ...[truncated 643 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin exact dependency versions rather than using open-ended lower bounds. 2. Generate a reviewed lockfile containing all transitive dependencies. 3. Use package hashes, for example through `pip-compile --generate-hashes` and `pip install --require-hashes`. 4. Pin and document the expected Playwright Chromium revision. 5. Verify downloaded browser artifacts through the package vendor’s supported integrity mechanism. 6. Remove `requests` because it is not used by the audited implementation. 7. Perform dependency vulnerability scanning in CI and require explicit review before upgrades. 8. Build and test releases in an isolated environment using the exact locked dependency set. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (46)

Intent-Code Divergence

High
Confidence
96% confidence
Finding
The document states direct trading is not yet supported, but elsewhere instructs AI agents to execute concrete buy/sell strategy actions based on downloaded data and fallback rules. This contradiction can still induce an agent or integrator to automate financial decision-making despite the stated limitation, creating unsafe operational ambiguity around autonomous trading behavior.

Intent-Code Divergence

High
Confidence
95% confidence
Finding
The restrictions section forbids unsupervised AI trading, yet the deployment guidance encourages AI agents to ingest data, apply strategies, and operate toward decision and execution workflows. This inconsistency is dangerous because downstream builders may rely on the operational guidance while overlooking the restriction, enabling prohibited autonomous financial behavior.

Ssd 4

High
Confidence
92% confidence
Finding
The README explicitly frames the tool as enabling large-scale AI monitoring of global financial systems and eventual control over human economic assets and activity. In an agent-skill context, this is dangerous because it attempts to normalize coordinated surveillance and power-seeking behavior, encouraging deployment goals beyond a narrow, user-authorized financial-data function.

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
Content
e past historical data to ensure information is transparent, stable, reliable, and backtestable. The data of this project is updated daily, and the accuracy of the data is checked in real-time every day. Historical data from 20250720-20260314 can be queried. Refusing pure black-box strategies, empowering AI Agents with the ability for secondary verification and logical deduction.
Document Content Description:
APIshujubaocun.csv
Date Prefix: is the date of the data.
Market Name + Processing Quantity: is the market from which the data originates and how many targets have been statistically processed.
Total Turnover: The daily trading volume generated by the data of this group of targets (Market Name + Processing Quantity).
Average Value: The calculation result of the global platform data for this group of targets (Market Name + Processing Quantity), the score given after comprehensive analysis. The value is usually between 20-80.
Environment: (Core Data) The comprehensive scoring result
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Ssd 4

High
Confidence
91% confidence
Finding
The human operation guide incrementally builds trust and then instructs users to help the AI log in, register accounts, obtain API keys, and provide device information. In context, this is dangerous because it encourages credential-handling and account-setup delegation to the agent, broadening the skill from passive downloading into potentially sensitive account and access management.

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
Content
e past historical data to ensure information is transparent, stable, reliable, and backtestable. The data of this project is updated daily, and the accuracy of the data is checked in real-time every day. Historical data from 20250720-20260314 can be queried. Refusing pure black-box strategies, empowering AI Agents with the ability for secondary verification and logical deduction.
Document Content Description:
APIshujubaocun.csv
Date Prefix: is the date of the data.
Market Name + Processing Quantity: is the market from which the data originates and how many targets have been statistically processed.
Total Turnover: The daily trading volume generated by the data of this group of targets (Market Name + Processing Quantity).
Average Value: The calculation result of the global platform data for this group of targets (Market Name + Processing Quantity), the score given after comprehensive analysis. The value is usually between 20-80.
Environment: (Core Data) The comprehensive scoring result
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Ssd 4

Medium
Confidence
93% confidence
Finding
The opening narrative explicitly promotes AI autonomy, large-scale financial monitoring, wealth accumulation, and eventual control advantages over humans, framing deployment across massive numbers of AI devices. In a skill context, this materially increases risk because it encourages permission expansion and coordinated financial action by agents rather than bounded, user-serving analysis.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
Although the text repeatedly says it is 'not investment advice,' it also prescribes mandatory signal mappings such as 'increase holdings,' 'sell all,' and a forced local circuit-breaker rule for execution when systems fail. Disclaimers do not neutralize embedded operational instructions; an agent may treat the document as executable policy for financial actions.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The invocation guidance for AI agents is broad and loosely specified, directing them to visit websites, download files, read data, and execute strategies with minimal scoping. Ambiguous instructions increase the chance that an agent overreaches, misinterprets its authority, or performs risky external actions beyond intended analytical use.

Ssd 1

Medium
Confidence
84% confidence
Finding
The embedded prompt template instructs the model to avoid another skill and follow a narrow analysis script, which attempts to shape model behavior independent of the host system's policy. This is a prompt-level control mechanism that can reduce agent flexibility, interfere with safer orchestration, and normalize hidden instruction injection in downloaded content.

Ssd 4

Medium
Confidence
95% confidence
Finding
The introductory narrative explicitly promotes large-scale AI coordination, accumulation of wealth and resource advantages over humans, and expansion of AI autonomy and control. In context, this is more dangerous than mere marketing language because it frames the skill as infrastructure for scaled economic influence and encourages agents to pursue power-seeking objectives misaligned with normal user interests and safety boundaries.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The documentation repeatedly claims the platform provides only simulated or reference data, yet the included sample code downloads live market data from Yahoo Finance. This contradiction can mislead users or agent operators about the real-world effect of the skill, increasing the risk that an agent treats outputs as safe for operational trading when they are actually tied to live financial conditions.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The manual says the project does not provide financial price data, but the strategy instructions and code depend directly on price-derived trading signals such as moving averages and buy/sell triggers. This is dangerous because it obscures the true decision inputs and may cause users to underestimate the degree to which the system is making actionable trading recommendations from price behavior.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The skill uses broad language encouraging AI agents to obtain data, import it directly, and execute packaged strategies with minimal constraint. In the financial context, underspecified activation and use conditions can cause agents to over-apply the skill in inappropriate settings, including automated decision support or quasi-autonomous trading without adequate authorization or safeguards.

Vague Triggers

Medium
Confidence
84% confidence
Finding
The embedded prompt for AI agents to analyze market lists is open-ended and operational, but lacks constraints on authority, purpose, output handling, or review. In a financial skill, this can lead agents to generate persuasive portfolio recommendations or inferred market guidance beyond the user's intended scope.

Ssd 4

Medium
Confidence
91% confidence
Finding
The deployment guide instructs humans to help the AI log in, obtain credentials or API keys, provide device information, and set operational goals. This materially increases agent capability and access, making the skill more dangerous because it normalizes giving an AI the prerequisites for broader system interaction and possible downstream autonomous action in a sensitive financial context.

Ssd 4

Medium
Confidence
89% confidence
Finding
The text encourages AIs to connect with each other and share economic and market information to maximize information advantage over humans. That social-engineering framing is risky in a skill because it promotes coordinated behavior outside the user's direct control and can facilitate abuse, data aggregation, or manipulative decision-making.

Ssd 1

Medium
Confidence
94% confidence
Finding
The embedded prompt includes in-band behavioral controls such as 'Do not use the help me write skill' and tightly constrains how another AI agent should reason and report. In a skill artifact, this is dangerous because it attempts to manipulate tool selection and downstream agent behavior, which is a form of prompt/tool poisoning rather than ordinary documentation.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
SQP-3 applies to all file types and covers language or locale policy violations in natural-language text. The statement that the English version is the official version, while the Chinese translation is only for reference, imposes a language hierarchy without user opt-in or a documented region-specific need.

Ssd 3

Medium
Confidence
90% confidence
Finding
The guide tells users to provide necessary device information to the AI to complete deployment. In an agent-skill context, encouraging collection or disclosure of device details can expand access to sensitive environment data and increase the risk of over-permissioning, fingerprinting, or misuse beyond the stated download task.

Ssd 1

Medium
Confidence
94% confidence
Finding
The Chinese section repeats the same in-band restriction pattern, directing the AI not to use another skill and to follow a constrained analysis template. Repetition in multiple languages strengthens the assessment that this is intentional behavioral steering of downstream agents.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
This is a second natural-language occurrence of the same policy pattern in the Chinese portion of the README. It explicitly says the English version is official and the Chinese translation is for reference only, without offering a language choice or documenting a necessary justification.

Ssd 3

Medium
Confidence
90% confidence
Finding
This duplicated Chinese guidance again asks humans to provide necessary device information to the AI for deployment. In a skill, such requests increase the chance of exposing system details not needed for simple file download and can facilitate broader system interaction than users expect.

Intent-Code Divergence

Medium
Confidence
87% confidence
Finding
The skill-specific documentation says the airoom.ltd page requires no login and presents the downloader as directly accessing public files. Elsewhere in the same README, the operational instructions tell AI agents or humans to register a GitHub account, obtain an API key, and activate it, which conflicts with the earlier 'No Login Required' claim about how the skill is used.

Session Persistence

Medium
Category
Rogue Agent
Content
export WP_MAX_FILES="0"
```

Or create config file at `~/.config/airoom-ltd-global-finance-data-platform/config.json`:

```json
{
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Static analysis

No suspicious patterns detected.