T09 · Insecure Skill Coding Practices
Note
- Location
- scripts/words.py:272
- Finding
- Undisclosed Transmission of User-Entered Vocabulary to a Third Party<![CDATA[ ## Vulnerability Details **File Location**: `scripts/words.py:272-288`, `scripts/words.py:562-566`, and `prompt-examples/AGENT_PROMPT_TEMPLATE.md:79-88` **Vulnerability Type**: Privacy exposure through automatic third-party network requests **Risk Level**: Low ### Vulnerable Code The helper embeds the user-supplied headword or phrase in a request to Cambridge Dictionary: ```python def fetch_rel(dict_path: str) -> list[str]: url = f"https://dictionary.cambridge.org/dictionary/{dict_path}/{requests.utils.quote(headword)}" try: r = requests.get( url, headers={ "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) learning-english-words/1.0", "Accept-Language": "en-US,en;q=0.9,pl;q=0.8", }, timeout=10, ) r.raise_for_status() except Exception: return [] return re.findall(r"/media/[^\s\"']+\.mp3", r.text) ``` Rendering triggers this network lookup whenever the card does not already contain an audio URI: ```python if args.fill_audio and not card.get("audio_uri"): audio = _cambridge_audio_url(head, prefer="us") if audio: con.execute("UPDATE cards SET audio_uri=?, updated_at=? WHERE id=?", (audio, now_iso(), card["id"])) con.commit() card["audio_uri"] = audio ``` The supplied Agent prompt makes the network-enabled rendering option part of its mandatory workflow: ```markdown ## Helper CLI (mandatory) Always use the helper for DB operations: - `python skill/scripts/words.py add ...` - `python skill/scripts/words.py render <headword> --fill-audio` - `python skill/scripts/words.py grade <card_id> <0-3>` When rendering: - send exactly the `text` output from `render` (no extra commentary), to keep formatting deterministic. ``` ### Technical Analysis The Skill is primarily a local SQLite vocabulary and spaced-repetition system. Pronunciation lookup is supplementary functionality and is not required for lo ...[truncated 2571 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Make local rendering the default** - Remove `--fill-audio` from the mandatory render command in `AGENT_PROMPT_TEMPLATE.md`. - Use `python skill/scripts/words.py render <headword>` unless the user explicitly requests online audio lookup. 2. **Require informed opt-in** - Before the first online lookup, explain that the headword or phrase will be sent to `dictionary.cambridge.org`. - Require explicit confirmation, particularly for multi-word phrases. 3. **Document network behavior** - Update `SKILL.md` to identify the destination, transmitted value, triggering commands, timeout, and potential logging implications. - Clearly distinguish local-only commands from network-enabled commands. 4. **Restrict eligible lookup values** - Reject or require additional confirmation for unusually long strings, email addresses, URLs, identifiers, or text resembling secrets. - Prefer automatic lookup only for short dictionary-like words. 5. **Provide a network-disable control** - Add an environment variable or command-line policy such as `ENGLISH_LEARN_CARDS_OFFLINE=1`. - Ensure that offline mode prevents every call to `_cambridge_audio_url()`. 6. **Use explicit network flags** - Rename or supplement `--fill-audio` with a flag that communicates its effect, such as `--fetch-audio-online`. - Do not initiate network traffic through options whose external disclosure implications are unclear. 7. **Minimize retained third-party data** - Continue storing only the resulting fixed audio URL. - Do not add review answers, definitions, examples, tags, or other database content to pronunciation requests. ]]>
