T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/finxdata.py:550
- Finding
- API Key Exposed Through Child-Process Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/finxdata.py:550-562` **Vulnerability Type**: Sensitive credential exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```python api_key = env_api_key() if api_key_required else None if api_key: args.extend(["-H", f"X-API-Key: {api_key}"]) if idempotency_key: args.extend(["-H", f"Idempotency-Key: {idempotency_key}"]) if agent_type: args.extend(["-H", f"x-agent-type: {agent_type}"]) args.append(url) return args def run_curl(args: list[str], *, agent_endpoint: bool = False) -> None: result = subprocess.run(args, capture_output=True, text=True, check=False) ``` ### Technical Analysis The code inserts `FINXDATA_API_KEY` directly into the argument vector of a spawned `curl` process as an HTTP header. Although the request uses HTTPS, transport encryption does not protect secrets exposed locally through process metadata. Depending on the operating system, process isolation settings, container configuration, and monitoring environment, another local process with sufficient visibility may inspect the `curl` command line through process-listing tools, process APIs, audit logs, or `/proc` interfaces. The complete API key can therefore remain observable for the duration of the request. The use of an argument list rather than `shell=True` prevents shell command injection, but it does not prevent command-line credential disclosure. The existing output sanitization also does not protect the child process argument vector. ### Attack Path 1. A user exports a valid `FINXDATA_API_KEY` and invokes an authenticated FinXData command. 2. The wrapper reads the key from the environment. 3. `build_curl_args` embeds the key in the argument `X-API-Key: <secret>`. 4. `subprocess.run` launches `curl` with that secret in its process arguments. 5. During execution, a local attacker, co-tenant, diagnostic agent, or monitoring service with process-inspection access reads the `curl` ...[truncated 970 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Prefer an in-process HTTPS client.** Replace the `curl` subprocess with a maintained Python HTTP library or the standard library so the API key can be assigned directly to an HTTP header without entering a child-process argument vector. 2. **Preserve existing network controls.** The replacement must retain TLS certificate verification, the fixed `https://api.finxdata.ai` origin allowlist, redirect prohibition, timeout limits, bounded retries, and the rule that API keys are not sent to health, summary, or Agent endpoints. 3. **If `curl` must remain, avoid command-line secrets.** Supply the sensitive header through a protected file descriptor or a temporary curl configuration file created with owner-only permissions such as mode `0600`. Delete the file immediately after use, including on exceptions and interruption. 4. **Do not move the key into another observable channel.** Avoid placing it in URLs, logs, exception messages, debug output, shell-expanded command strings, or broadly inherited environment variables. 5. **Minimize secret lifetime.** Read the credential only when required, restrict its propagation to the request implementation, and avoid retaining additional copies. 6. **Add regression tests.** Verify that authenticated requests work while the generated process arguments, logs, and errors never contain the API key. Also verify that unauthenticated and Agent endpoints never receive it. 7. **Rotate potentially exposed credentials.** Users who executed the current implementation in shared or monitored environments should revoke and replace the affected API keys. ]]>
