T09 · Insecure Skill Coding Practices
- Location
scripts/ingest_url.py:97- Finding
Full User-Supplied URLs Are Disclosed to a Third-Party Extraction Service
- Content
View full analysis
Vulnerability Details
File Location:
scripts/ingest_url.py, lines 97–103
Vulnerability Type: Sensitive information exposure through third-party URL proxying
Risk Level: MediumVulnerable Code
python def fetch_r_jina(url: str, timeout: int = 40) -> str: # r.jina.ai returns a plain-text extracted representation. rurl = "https://r.jina.ai/" + url headers = {"User-Agent": "Mozilla/5.0"} r = requests.get(rurl, headers=headers, timeout=timeout) r.raise_for_status() return r.textTechnical Analysis
The function embeds the complete user-supplied URL in a request sent to the external
r.jina.aiservice. No validation or redaction is performed before transmission.Consequently, the external service can receive sensitive URL components, including:
- Query parameters containing access tokens or signed-resource credentials
- Password-reset or account-verification links
- Private document sharing URLs
- Invitation codes and session identifiers
- Credentials included in URL user-information fields
- Private resource names and identifiers
Use of
r.jina.aiis documented inSKILL.md, so the transmission is not covert. However, the implementation does not enforce the documentation's recommendation to redact sensitive data. It also lacks a consent gate, direct-fetch alternative, domain policy, and sensitive-parameter detection.Sending public URLs to an extraction service supports the declared functionality. Sending arbitrary URLs in full exceeds the minimum data disclosure needed when the URL includes credentials or private identifiers.
Attack Path
- A user asks the Skill to ingest a private, signed, or tokenized URL.
normalize_url()preserves the URL's query string and any embedded credentials.- The URL reaches
fetch_r_jina()without a sensitivity check. - The function constructs
https://r.jina.ai/plus the complete original URL. - The request exposes the complete URL to the third-party serv ...[truncated 860 chars]
- Remediation
View remediation
Remediation Suggestions
-
Reject URL credentials
- Parse URLs with
urllib.parse.urlsplit. - Reject URLs whose authority contains a username or password.
- Permit only expected
httpsURLs.
- Parse URLs with
-
Minimize query-string disclosure
- Strip query strings and fragments by default.
- Maintain a denylist for credential-like parameter names such as
token,access_token,key,secret,signature,sig,auth,session, andcode. - Prefer a narrowly scoped allowlist of parameters required for known public content providers.
-
Require informed confirmation
- Display the destination host and a redacted form of the URL before sending it to a third-party proxy.
- Require explicit approval when query parameters are present or the domain is not on an approved public-domain list.
-
Provide a privacy-preserving path
- Offer direct retrieval as the default where technically possible.
- Use the external extractor only as an explicit fallback.
- Do not proxy private-network, localhost, or authenticated resource URLs.
-
Improve handling and documentation
- Clearly identify
r.jina.aias a third-party data processor. - Explain that submitted URLs may be visible in service and intermediary logs.
- Redact sensitive parameters from console output, stored metadata, and error messages.
- Clearly identify
-
Add automated tests
- Verify that URLs containing user information are rejected.
- Verify that sensitive query parameters are removed or require confirmation.
- Verify that ordinary public URLs continue to work as intended.
-
