Back to skill

Security audit

iFind http API

Security checks for vulnerabilities and agentic risk

Overview

This iFinD skill has a coherent purpose, but it needs Review because it persistently handles a long-lived account refresh token and exposes broad API access with imperfect credential safeguards.

Install only if you are comfortable letting the skill access your iFinD account token, store it locally, and make authenticated QuantAPI calls. Prefer a dedicated low-scope iFinD token, avoid passing the token on the command line, verify the credential file permissions yourself, and review any use of the generic endpoint mode before allowing calls.

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

Warning
Location
scripts/ifind_token_store.py:17
Finding
Credential File Is Created Without Fail-Closed Permission Enforcement<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ifind_token_store.py:17-21, 55-56` **Vulnerability Type**: Unsafe sensitive-file creation and silently ignored permission errors **Risk Level**: Medium ### Vulnerable Code ```python def _chmod_owner_only(path: Path) -> None: try: path.chmod(stat.S_IRUSR | stat.S_IWUSR) except OSError: pass ``` ```python STORE_PATH.write_text( json.dumps(payload, ensure_ascii=False, indent=2), encoding='utf-8' ) _chmod_owner_only(STORE_PATH) ``` ### Technical Analysis The long-lived iFinD refresh token is first written using `Path.write_text()`. Its initial permissions therefore depend on the process umask. Mode `0600` is applied only after the complete token has already been written. This creates a time-of-check/time-of-protection interval during which the credential file may have broader permissions than intended. More importantly, `_chmod_owner_only()` suppresses every `OSError`, so the operation can report successful token storage even if permission hardening fails. The containing credential directory is also created without explicitly verifying or enforcing owner-only permissions. The credential path is legitimate and necessary for the skill's declared functionality, but the implementation does not reliably enforce the documented owner-only storage policy. ### Attack Path 1. The user invokes the token-storage command. 2. `credentials.json` is created with permissions determined by the current umask. 3. A local process or another account with directory access reads the file before permission hardening, or permission hardening fails. 4. The exception is silently ignored and the script still reports that the token was stored successfully. 5. The observer uses the exposed refresh token to request an iFinD access token and perform API calls under the victim's account. Exploitation requires local access and sufficient filesystem traversal permissions; no remote exploitation pat ...[truncated 397 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create and verify the credential directory with mode `0700`. - Create a temporary file atomically with mode `0600`, for example with `os.open()` using `O_CREAT | O_EXCL` and an explicit mode. - Write and flush the token, then atomically replace the destination with `os.replace()`. - Verify the resulting file's ownership, type, and mode after replacement. - Refuse to report success if permission enforcement or verification fails. - Avoid following symbolic links and reject a credential path that is not a regular file owned by the current user. - Consider using the operating system's credential manager or keyring instead of a plaintext JSON file. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/ifind_token_store.py:101
Finding
Refresh Token Is Accepted Through a Command-Line Argument<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ifind_token_store.py:101-102`; documented at `SKILL.md:46-48` and `references/token-and-storage.md:48-52` **Vulnerability Type**: Sensitive credential exposure through process arguments and shell history **Risk Level**: Low ### Vulnerable Code ```python p_set = sub.add_parser('set') p_set.add_argument('--token', required=True) ``` The documented invocation is: ```bash python3 scripts/ifind_token_store.py set --token '<TOKEN>' ``` ### Technical Analysis Passing a refresh token as a command-line argument places it in the process argument vector. Depending on the operating system and host configuration, command arguments may be visible to other local users, process-monitoring tools, audit systems, diagnostic collectors, or parent processes. An interactively entered command may also be retained in shell history. This conflicts with the project's stated rule to avoid placing the token in shell history and unnecessarily exposes a long-lived credential outside the protected credential store. ### Attack Path 1. The user follows the documented command and substitutes the real refresh token for the placeholder. 2. The shell records the command in history, or the running process exposes the token through its argument vector. 3. A local user, monitoring agent, log collector, or later reader of the history file obtains the token. 4. The observer exchanges the refresh token for an access token at the official iFinD API. 5. The observer performs API calls using the victim's account permissions and quota. Exploitation requires access to process metadata, shell history, or collected command telemetry. ### Impact Assessment Disclosure permits unauthorized use of the affected iFinD account within the API permissions associated with the token. It may expose licensed data and account metadata or consume available API quotas. The issue does not itself grant operating-system privileges. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Replace `--token` with concealed interactive input using `getpass.getpass()`. - For noninteractive use, accept the token through standard input or a specifically designated file descriptor. - Do not echo the token or include it in success and error messages. - Remove the command-line token examples from `SKILL.md` and `references/token-and-storage.md`. - If an environment-variable override remains supported, document that environment variables may also be exposed by process inspection or diagnostic tooling and should be limited to controlled, temporary environments. - Recommend removing any previously entered token commands from shell history and rotating a token if exposure is suspected. ]]>

T08 · Insecure Dependencies

Note
Location
scripts/requirements.txt:1
Finding
Runtime Dependency Is Not Reproducibly Pinned<![CDATA[ ## Vulnerability Details **File Location**: `scripts/requirements.txt:1` **Vulnerability Type**: Unbounded future dependency resolution without integrity hashes **Risk Level**: Low ### Vulnerable Code ```text requests>=2.31.0 ``` The dependency is installed through: ```bash python3 -m pip install -r scripts/requirements.txt ``` ### Technical Analysis The lower-bound constraint allows pip to install any later version of `requests` accepted by dependency resolution. The requirements file also contains no package hashes, despite being described in `SKILL.md` as a pinned dependency file. Consequently, an installation can retrieve code that was not represented by or reviewed as part of this skill package. This makes builds non-reproducible and increases exposure to future compromised releases, unexpected dependency changes, or compatibility regressions. No malicious or typosquatted dependency was found in the current project; the risk is caused by unrestricted future resolution and missing integrity verification. ### Attack Path 1. The environment does not already contain the required dependency. 2. The user or agent runs the documented pip installation command. 3. Pip resolves a later version of `requests` and its transitive dependencies from the configured package index. 4. If a selected future release or package-index response is compromised, installation executes or installs attacker-controlled package content. 5. That content runs with the privileges of the account performing the installation and can access data available to that account. This path is conditional on compromise of the selected distribution, package source, or resolution environment; the audited requirements file does not itself reference a known malicious package. ### Impact Assessment A compromised dependency could execute code with the privileges of the installing user, access local files and credentials available to that user, alter the Python environment, or intercept su ...[truncated 140 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace the lower-bound constraint with an exact, reviewed version pin. - Generate and verify cryptographic hashes for all direct and transitive packages, and install with `pip --require-hashes`. - Use a lock file produced from a controlled dependency-resolution process. - Install into an isolated virtual environment rather than the system Python environment. - Review and update pinned versions through a controlled maintenance process that includes vulnerability scanning and compatibility testing. - Correct the documentation so it does not describe a lower-bound requirement as pinned. ]]>
Vulnerability Patterns
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (13)

Credential Access

High
Category
Privilege Escalation
Content
## Token storage policy

- Storage path: `~/.openclaw/skills/ifind/credentials.json`
- File permission target: owner read/write only (`600` on POSIX)
- The store script writes the file and tightens permissions automatically.
- The request script reads the refresh_token from that file unless `IFIND_REFRESH_TOKEN` is already present in the environment.
Confidence
86% confidence
Finding
The skill instructs the agent to obtain, store, and reuse a refresh token in a local credentials file, which is credential handling with meaningful security risk. Even with a 600 permission target, local plaintext token storage and preference for environment/file-based reuse can expose long-lived credentials to other processes, misconfigured systems, backups, logs, or later agent actions.

Credential Access

High
Category
Privilege Escalation
Content
from pathlib import Path

STORE_DIR = Path.home() / '.openclaw' / 'skills' / 'ifind'
STORE_PATH = STORE_DIR / 'credentials.json'


def _ensure_dir() -> None:
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
from pathlib import Path

STORE_DIR = Path.home() / '.openclaw' / 'skills' / 'ifind'
STORE_PATH = STORE_DIR / 'credentials.json'


def _ensure_dir() -> None:
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill describes capabilities that include shell execution, network access, environment access, and file read/write, but it does not declare any explicit tool scope or permissions boundary. That increases the chance an agent will use broader capabilities than necessary, especially since the workflow includes token handling and web access.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
`python3 scripts/ifind_token_store.py set --token '<TOKEN>'`
4. Only fall back to asking the user to provide the token if the browser path is unavailable or login cannot be completed.

Never ask the user to paste shell commands that would echo the token back into chat. Never print the token after storing it.

## Preferred token acquisition workflow
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The workflow explicitly directs use of a Chinese-language client path (`iFinD 超级命令客户端 → 工具 → refresh_token 查询`) without offering an alternative language choice or noting that this is locale-specific. This can violate language/locale policy when users are not opted into Chinese-language tooling.

External Transmission

Medium
Category
Data Exfiltration
Content
for attempt in range(max_retries):
            try:
                response = requests.post(url, headers=headers, json=payload, timeout=60)
                response.raise_for_status()
                result = response.json()
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The script exposes a generic `endpoint` subcommand that forwards a user-supplied endpoint name and arbitrary JSON payload directly into the internal `_call_api` method, bypassing the narrower preset-based interface described by the skill metadata. This expands the accessible API surface beyond the declared market/macro/fund/code-conversion/calendar/report/portfolio use cases and weakens policy enforcement, allowing callers to invoke unintended or sensitive QuantAPI operations with the locally stored refresh token.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This code stores a refresh token on disk in a local credentials file, which is a safety-sensitive operation involving credential persistence. Although the function prints a success message after writing, it does not disclose beforehand that a sensitive token will be stored locally, and there is no inline docstring or comment warning about that behavior.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
This markdown file is largely written in Chinese, but line L240 instructs users to read the original file for fuller details in English phrasing without stating any language preference or offering localization options. That can create a language/locale policy issue if the skill implicitly assumes users can work across mixed languages without opt-in.

Missing User Warnings

Low
Confidence
81% confidence
Finding
The script reads the IFIND_REFRESH_TOKEN environment variable, which is a sensitive credential source. The file contains no docstring, comment, or other explicit warning that the skill accesses credentials from the environment, so users may not realize credential material is being consumed this way.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
Confidence
91% confidence
Finding
The dependency is specified as `requests>=2.31.0`, which allows any future version and does not guarantee a reproducible or reviewed install. This creates supply-chain uncertainty and can result in deployment of versions with breaking changes or newly introduced vulnerabilities, especially in a skill that performs HTTP requests to an external financial API.

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
86% confidence
Finding
The manifest references `requests` without pinning an exact version, so it is not possible to verify whether the installed package includes fixes for known advisories. In this skill's context, which is explicitly intended to call HTTP endpoints and handle authentication tokens, an affected `requests` version could expose credentials or weaken transport/security behavior.

Static analysis

No suspicious patterns detected.