T09 · Insecure Skill Coding Practices
Error
- Location
- cli.py:406
- Finding
- Stored Financial Profile Transmitted in External Search Queries<![CDATA[ ## Vulnerability Details **File Location**: `db.py:174-205`, `cli.py:406-410` **Vulnerability Type**: Sensitive financial information exposure to a third-party search provider **Risk Level**: High ### Vulnerable Code ```python def profile_as_context(cards: list[str] | None = None) -> str: """ Return a compact natural-language summary of the user profile suitable for injecting into a Brave Search query or LLM prompt. """ p = get_profile() parts = [] spend_fields = [ ("dining_monthly", "dining"), ("groceries_monthly", "groceries"), ("travel_monthly", "travel"), ("gas_monthly", "gas"), ("other_monthly", "other"), ] spend_parts = [f"${p[k]}/mo {label}" for k, label in spend_fields if p.get(k)] if spend_parts: parts.append("Spending: " + ", ".join(spend_parts)) if p.get("annual_fee_tolerance"): parts.append(f"Max annual fee: ${p['annual_fee_tolerance']}") if p.get("points_programs"): parts.append(f"Points programs: {p['points_programs']}") if p.get("home_airport"): parts.append(f"Home airport: {p['home_airport']}") if p.get("goal"): parts.append(f"Goal: {p['goal']}") if p.get("preferences"): parts.append(f"Preferences: {p['preferences']}") if cards: parts.append(f"Current cards: {', '.join(cards)}") return " | ".join(parts) if parts else "" ``` ```python # Enrich with saved profile context if available saved_ctx = _db.profile_as_context(cards=_db.get_card_names()) ctx = f"{saved_ctx} | " if saved_ctx else "" query = f"best credit cards {ctx}{profile} {pref}US 2025 site:nerdwallet.com OR site:thepointsguy.com OR site:doctorofcredit.com OR site:uscreditcardguide.com" _run_search(_get_wrapper(key), query, "recommend", as_json) ``` ### Technical Analysis The `recommend` command automatically reads the complete saved profile and wallet composition, serializes them into natural-language cont ...[truncated 1851 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not automatically include the complete saved profile in external search queries. 2. Default to a minimized query containing only the spending categories necessary for the requested recommendation. 3. Exclude the home airport, goals, preferences, and wallet names unless the user explicitly selects those fields. 4. Display the exact outbound query or a field-level summary and require confirmation before sending sensitive data. 5. Add a local-only mode that generates recommendations from bundled information without network transmission. 6. Separate search retrieval from personalization: search for generic card information first, then apply the private profile locally. 7. Clearly document which fields leave the device, the destination service, and the applicable retention policy. 8. Add tests asserting that sensitive profile fields are absent from network queries unless explicit consent is recorded. ]]>
