T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/recall_radar.py:95
- Finding
- Optional openFDA API Key Exposed Through Verbose Logging<![CDATA[ ## Vulnerability Details **File Location**: `scripts/recall_radar.py:95-101` **Vulnerability Type**: Sensitive credential exposure through diagnostic output **Risk Level**: Medium ### Vulnerable Code ```python def fetch_recalls(api_key=None, limit=1000, verbose=False): q = urllib.parse.quote('status:"Ongoing"') url = f"{OPENFDA}?search={q}&limit={limit}" if api_key: url += f"&api_key={api_key}" if verbose: print(f"# fetching {url}", file=sys.stderr) ``` ### Technical Analysis The optional openFDA API key is appended directly to the request URL. When the user enables `--verbose`, the complete URL—including the unredacted API key—is written to standard error. Standard error may be retained by CI/CD systems, shell-session recorders, scheduled-job logs, monitoring platforms, container logs, or shared terminal capture systems. Anyone able to read those records could recover the credential. The live network request itself is consistent with the Skill's declared purpose: it contacts the documented openFDA HTTPS endpoint to retrieve ongoing recall records. Pantry brands, products, UPCs, lots, and notes are not added to the request. The vulnerability is therefore the unnecessary disclosure of the API key in diagnostic output, not unauthorized transmission of pantry information. ### Attack Path 1. A user supplies an openFDA key through `--api-key` or the `OPENFDA_API_KEY` environment variable. 2. The user runs the `match` or `audit` command with `--verbose`. 3. `get_recalls()` passes the key to `fetch_recalls()`. 4. `fetch_recalls()` appends the key to the URL as the `api_key` query parameter. 5. Verbose mode prints the complete URL to standard error. 6. A local user, log reader, CI operator, monitoring-system user, or other party with access to retained output extracts the API key. 7. The party reuses the key to make requests attributed to the victim and consume the associated openFDA quota. ### Impact Assessment Succe ...[truncated 511 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Never print a URL containing the real API key. Redact the value before logging: ```python if verbose: safe_url = url if api_key: safe_url = safe_url.replace( f"api_key={urllib.parse.quote(str(api_key))}", "api_key=[REDACTED]", ) print(f"# fetching {safe_url}", file=sys.stderr) ``` 2. Prefer constructing query parameters with `urllib.parse.urlencode()` instead of manual string concatenation, and generate a separate sanitized representation for diagnostics. 3. If supported by openFDA, transmit credentials through an authorization header rather than a query parameter. Query parameters are more likely to appear in proxy, access, and diagnostic logs. 4. Keep verbose output limited to non-sensitive information, such as the hostname, endpoint path, recall status, and result limit: ```python if verbose: print( f"# fetching {OPENFDA} " f"(status=Ongoing, limit={limit}, api_key={'set' if api_key else 'unset'})", file=sys.stderr, ) ``` 5. Add an automated test that invokes verbose mode with a sentinel API key and asserts that the sentinel never appears in stdout or stderr. 6. Users who previously ran keyed requests with `--verbose` should inspect relevant logs and rotate the openFDA key if those logs were accessible to untrusted parties. ]]>
