T09 · Insecure Skill Coding Practices
- Location
scripts/catch_api.py:59- Finding
Credentials, Authentication Tokens, and Customs Invoices May Be Transmitted over Plaintext HTTP
- Content
View full analysis
str: if not BASE: sys.exit("set $CATCH_BASE_URL to the portal origin, e.g. https://portal.example.com") return BASE ``` ```python def login() -> str: user, password = os.environ.get("CATCH_USER"), os.environ.get("CATCH_PASS") if not (user and password): sys.exit("set $CATCH_USER and $CATCH_PASS") r = _post("/v1/user/login", {"username": user, "password": password}, auth=False) ``` ```python def _req(method, path, data=None, headers=None, auth=True): h = dict(COMMON) if auth: token = load_token() if not token: sys.exit("no token — run `python3 catch_api.py login` or set $CATCH_TOKEN") h["x-token"] = token h.update(headers or {}) req = urllib.request.Request(_base() + path, data=data, headers=h, method=method) try: with urllib.request.urlopen(req, timeout=120) as resp: return json.loads(resp.read()) ``` The related documentation explicitly describes upload “over pure HTTP” and allows a configurable portal origin: ```markdown export CATCH_BASE_URL=https://portal.example.com ``` ### Technical Analysis Uploading customs invoices and authenticating to the forwarder portal are necessary for the declared functionality. However, the implementation accepts any value in `CATCH_BASE_URL` and does not verify that its scheme is HTTPS. If the variable is accidentally or maliciously configured with an `http://` URL, the following information is transmitted without encryption: - Portal username and password during `/v1/user/login` - The reusable `x-token` authentication token - Complete customs invoice files - FBA shipment and box identifiers - Amazon r ...[truncated 1567 chars]- Remediation
View remediation
str: if not BASE: sys.exit("set $CATCH_BASE_URL") parsed = urlsplit(BASE) if parsed.scheme != "https" or not parsed.hostname: sys.exit("CATCH_BASE_URL must be a valid HTTPS origin") if parsed.username or parsed.password or parsed.query or parsed.fragment: sys.exit("CATCH_BASE_URL must contain only a trusted HTTPS origin") return f"https://{parsed.netloc}" ``` ]]>
