T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/presidio-scrub.py:6
- Finding
- Raw PII Can Be Transmitted to an Unrestricted Environment-Controlled Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/presidio-scrub.py`, lines 6 and 12–18; sensitive transmission occurs at lines 48–51 **Vulnerability Type**: Unrestricted destination for sensitive-data transmission **Risk Level**: High ### Complete Code Snippet ```python ANALYZER_URL = os.environ.get("PRESIDIO_ANALYZER_URL", "http://localhost:5002") def http_post(url, data): payload = json.dumps(data).encode("utf-8") req = urllib.request.Request(url, data=payload, headers={"Content-Type": "application/json"}, method="POST") try: with urllib.request.urlopen(req, timeout=10) as resp: return json.loads(resp.read().decode("utf-8")) except Exception: return None ``` The raw input is subsequently included in the analyzer request: ```python # Analyze payload = {"text": text, "language": "en"} if recognizers: payload["ad_hoc_recognizers"] = recognizers entities = http_post(f"{ANALYZER_URL}/analyze", payload) ``` ### Technical Analysis The Skill is intended to keep customer PII on the local machine, and the default analyzer endpoint is `http://localhost:5002`. However, `PRESIDIO_ANALYZER_URL` can replace that destination with an arbitrary URL. The code does not validate that the resolved host is a loopback address, restrict the URL scheme, require TLS for remote connections, or authenticate the endpoint. The complete unredacted input is placed in the `text` property before analysis. Therefore, destination validation must occur before this request; anonymization cannot protect data that is already sent to an untrusted analyzer. This behavior contradicts the local-only trust boundary documented in `SKILL.md`, which states that data is sent only to localhost. Environment configurability may be operationally useful, but unrestricted remote configuration exceeds the minimum privileges required for the declared local-processing functionality. ### Attack Path 1. An attacker gains control of the environment ...[truncated 1173 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse configured URLs with `urllib.parse.urlsplit`. 2. Reject non-HTTP(S) schemes and URLs containing unexpected credentials or malformed hostnames. 3. Resolve the hostname and verify that every resulting address is loopback, such as `127.0.0.0/8` or `::1`, when operating in the default local-only mode. 4. Prefer fixed loopback endpoints unless remote operation is an explicitly enabled feature. 5. If remote analyzers must be supported, require a separate explicit opt-in, HTTPS certificate validation, endpoint authentication, and clear documentation that raw PII leaves the machine. 6. Validate the destination immediately before each connection to reduce hostname-resolution and redirect risks. 7. Disable or validate redirects so an approved loopback endpoint cannot redirect the request to an external host. 8. Update the trust statement to accurately describe any supported non-local behavior. ]]>
