T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/housing_scout/housing_scout.mjs:231
- Finding
- Unrestricted User-Supplied URL Disclosure Through a Third-Party Fetch Proxy<![CDATA[ ## Vulnerability Details **File Location**: `scripts/housing_scout/housing_scout.mjs:231-241`; `scripts/housing_scout/providers/redfin.mjs:135-140` **Vulnerability Type**: Unvalidated URL forwarding and third-party data disclosure **Risk Level**: Medium ### Vulnerable Code ```js async function buildSubjectFromRedfinUrl(redfinUrl, results = []) { const hit = results.find((x) => String(x.url || "").replace(/\/$/, "") === String(redfinUrl || "").replace(/\/$/, "")); if (hit) return buildSubjectFromListing(hit, { status: "for_sale" }); const mirror = `https://r.jina.ai/http://${String(redfinUrl).replace(/^https?:\/\//, "")}`; const res = await fetch(mirror, { headers: { "user-agent": "Mozilla/5.0" } }); if (!res.ok) throw new Error(`Failed to fetch redfin-url subject (${res.status})`); const text = await res.text(); return parseRedfinTitleSubject(text, redfinUrl); } ``` A second unrestricted forwarding helper is present in the Redfin provider: ```js async function fetchViaJina(url) { const mirror = `https://r.jina.ai/http://${url.replace(/^https?:\/\//, "")}`; const res = await fetch(mirror, { headers: { "user-agent": "Mozilla/5.0" } }); if (!res.ok) throw new Error(`Jina fetch failed ${res.status}`); return res.text(); } ``` ### Technical Analysis The `--redfin-url` argument is treated as an arbitrary string and embedded into a request to the external `r.jina.ai` fetch service. The implementation does not use `new URL()` to validate the input and does not enforce: - An HTTPS source URL. - A Redfin-owned hostname. - Standard destination ports. - The absence of embedded usernames or passwords. - Rejection of localhost, private, link-local, reserved, or cloud metadata destinations. - Redirect restrictions. - Removal of sensitive URL query parameters or fragments. The documentation warns users not to supply private or internal URLs, but this warning is not an enforceable security boundary. A caller can still pass such a URL di ...[truncated 2776 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse every externally supplied URL using `new URL()` and reject malformed input. 2. Require the source protocol to be exactly `https:`. 3. Enforce a strict hostname allowlist, such as `www.redfin.com` and any explicitly reviewed Redfin subdomains. Avoid suffix checks that would accept domains such as `redfin.com.attacker.example`. 4. Reject URLs containing `username`, `password`, nonstandard ports, or unnecessary sensitive query parameters. 5. Reject IP-literal destinations and resolve hostnames before use. Block loopback, private, link-local, multicast, reserved, and cloud metadata address ranges for both IPv4 and IPv6. 6. Apply validation at every trust boundary: - When accepting `--redfin-url`. - When importing cache records. - Immediately before each outbound request. 7. Disable automatic redirect following or validate every redirect destination against the same protocol, host, port, and IP-address policy. 8. Do not pass arbitrary destinations to a third-party proxy. Prefer direct requests to an approved Redfin endpoint where operationally possible. 9. If a proxy remains necessary, explicitly request user consent and document what URL and listing information is disclosed to that service. 10. Add negative tests covering localhost, RFC1918 addresses, link-local and metadata addresses, IPv6 loopback/private ranges, encoded hostnames, embedded credentials, nonstandard ports, deceptive subdomains, and redirects to disallowed destinations. ]]>
