Back to skill

Security audit

English Learn Cards

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local vocabulary flashcard skill, with a privacy-relevant online audio lookup that users should understand before enabling.

Install only if you are comfortable with a local SQLite vocabulary database and optional online pronunciation lookup. For privacy-sensitive use, remove `--fill-audio` from the prompt template or require explicit consent before sending a headword or phrase to Cambridge Dictionary.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

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. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill declares itself platform-agnostic and instructs use of a helper CLI plus an environment-controlled database path, but it does not declare any explicit tool scope or permission boundaries. In an agent ecosystem, undocumented access to environment variables and potential network-capable runtime behavior increases the chance of overbroad tool use, unintended data exposure, or execution in contexts with more privileges than necessary.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The skill name and description present the workflow as specifically for English vocabulary learning, and the document does not offer any user opt-in or alternative language/locale handling. Under the policy rule, forcing a specific language without user choice is a natural-language policy concern unless the constraint is explicitly justified.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The prompt explicitly says to teach vocabulary in English, while only optionally adding a second language for explanations. This imposes a language default rather than offering the user a language choice or requiring opt-in.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The trigger phrase `teach me` is broad and conversational, so it can match many normal user requests unrelated to this specific vocabulary skill. That increases the chance of accidental activation and context hijacking, especially when paired with other agents or assistant behaviors in the same chat surface.

Vague Triggers

Medium
Confidence
91% confidence
Finding
Using `help` as a bare trigger is overly generic and likely to appear in ordinary conversation or as a request to the host assistant, causing unintended activation of this skill. In a multi-skill or general chat environment, that can lead to command confusion, unexpected DB-backed actions, and reduced user control over which capability is being invoked.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest describes a flashcard-based English vocabulary skill with SQLite and SRS, which suggests local study-card storage and review logic. This file additionally imports `requests` and later fetches audio URLs from Cambridge Dictionary, introducing external network behavior not conveyed by the manifest description.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The `_cambridge_audio_url` helper issues HTTP requests to a third-party website and scrapes HTML to discover MP3 resources. For a skill whose stated purpose is flashcard-based vocabulary learning with SQLite and spaced repetition, network scraping is an additional capability that is not clearly necessary or declared in the manifest context provided.

Static analysis

No suspicious patterns detected.