T09 · Insecure Skill Coding Practices
- Location
- scripts/add_abstracts.py:52
- Finding
- Untrusted Abstract Injection Through Plaintext arXiv Transport<![CDATA[ ## Vulnerability Details **File Location**: `scripts/add_abstracts.py:52-55`, `scripts/add_abstracts.py:253-260`; also documented in `SKILL.md:31` **Vulnerability Type**: Plaintext external API transport combined with unsafe BibTeX serialization **Risk Level**: Medium ### Vulnerable Code The arXiv API request uses unencrypted HTTP: ```python url = f'http://export.arxiv.org/api/query?search_query={urllib.parse.quote(query)}&max_results=5' req = urllib.request.Request(url, headers={'User-Agent': 'AbstractSearcher/1.0'}) with urllib.request.urlopen(req, timeout=15) as response: xml_content = response.read().decode('utf-8') ``` The remotely supplied abstract is inserted into BibTeX without escaping braces or potentially dangerous LaTeX control sequences: ```python def clean_abstract(text: str) -> str: """Clean abstract text for BibTeX""" # Remove excessive whitespace text = re.sub(r'\s+', ' ', text).strip() # Remove or escape problematic characters (minimal) text = text.replace('\n', ' ') text = text.replace('\r', ' ') # Escape curly braces that aren't already escaped # text = text.replace('{', '\\{').replace('}', '\\}') return text ``` ```python if abstract: clean_abs = clean_abstract(abstract) lines.append(f" abstract={{{clean_abs}}},") ``` ### Technical Analysis Because the arXiv request is made over plaintext HTTP, it lacks transport confidentiality and server authentication. An attacker able to intercept or modify network traffic can replace the API response with forged XML. The script performs only a lenient title check and accepts the supplied summary as the abstract. `clean_abstract()` normalizes whitespace but does not safely encode BibTeX syntax, braces, or LaTeX control sequences. Brace escaping is explicitly commented out. Consequently, a forged abstract can terminate or restructure the generated field or introduce attacker-controlled LaTeX content. The Python script itself does not ex ...[truncated 1755 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace the plaintext endpoint with the authenticated HTTPS endpoint: ```python url = ( 'https://export.arxiv.org/api/query' f'?search_query={urllib.parse.quote(query)}&max_results=5' ) ``` 2. Do not disable TLS certificate verification. Use the platform trust store and reject redirects that downgrade from HTTPS to HTTP. 3. Treat all API response fields as untrusted. Serialize output through a maintained BibTeX library rather than constructing entries with string interpolation. 4. If manual serialization remains necessary, implement context-aware escaping for braces, backslashes, percent signs, and other BibTeX or LaTeX metacharacters. Prefer a conservative allowlist or encode abstract text so that it cannot terminate its field. 5. Consider rejecting unexpected control sequences, unmatched braces, NUL bytes, and other control characters in remote abstracts. 6. Strengthen record matching by comparing normalized complete titles and available identifiers such as DOI or arXiv ID instead of accepting any result with three matching words among the first five. 7. Add security tests using forged abstracts containing closing braces, additional BibTeX entries, LaTeX commands, and malformed Unicode. Verify that each payload remains inert text after serialization and downstream parsing. ]]>
