T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/macro_data.py:51
- Finding
- API Keys May Be Disclosed Through Raw Exception Output<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/crypto_onchain.py:54-65, 91-92` - `scripts/macro_data.py:51-59, 88-90` - `scripts/market_data.py:101-112, 147-149` - `scripts/market_data.py:163-170, 190-192` - `scripts/market_data.py:197-203, 220-222` - `scripts/market_data.py:227-233, 254-256` - `scripts/sentiment_news.py:81-90, 115-117` **Vulnerability Type**: Sensitive credential exposure through error messages **Risk Level**: Medium ### Vulnerable Code Representative example from `scripts/macro_data.py`: ```python url = f"{self.BASE_URL}/series/observations" params = { "series_id": series_id, "api_key": self.api_key, "file_type": "json", "sort_order": "desc", "limit": 100 } if observation_start: params["observation_start"] = observation_start try: response = self.session.get(url, params=params, timeout=15) response.raise_for_status() data = response.json() observations = data.get("observations", []) if not observations: return {"series_id": series_id, "error": "No data found"} latest = None for obs in observations: if obs.get("value") and obs["value"] != ".": latest = obs break if not latest: return {"series_id": series_id, "error": "No valid data"} return { "series_id": series_id, "latest_value": float(latest["value"]), "latest_date": latest["date"], "observations": [ { "date": o["date"], "value": float(o["value"]) if o["value"] and o["value"] != "." else None } for o in observations[:30] ] } except Exception as e: print(f"FRED API error: {e}") return {"series_id": series_id, "error": str(e)} ``` Equivalent query-string credential patterns appear in the other affected clients: ```python # scripts/crypto_onchain.py params = { "a": "BTC", "s": int(start_date.timestam ...[truncated 3418 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Use authentication headers instead of query-string credentials wherever the provider supports them. 2. Never print or return raw `requests` exceptions from authenticated requests. 3. Replace broad exception output with a fixed message and sanitized structured logging: ```python except requests.exceptions.RequestException as exc: logger.error( f"FRED request failed: {type(exc).__name__}" ) return { "series_id": series_id, "error": "The FRED request failed." } ``` 4. Apply `safe_api_call` or an equivalent centralized wrapper consistently to every network-facing method. 5. Add a URL-redaction function that removes credential parameters such as `api_key`, `apikey`, `apiKey`, `token`, and `access_token` before any URL is logged. 6. Ensure response bodies and provider error messages are also sanitized before logging. 7. Add automated tests that deliberately raise `HTTPError`, timeout, proxy, redirect, and connection exceptions and verify that configured secrets do not appear in captured output. 8. Rotate any API keys that may already have appeared in logs or agent transcripts. ]]>
