T09 · Insecure Skill Coding Practices
- Location
scripts/website_phone_number_finder_actor.py:173- Finding
Apify API Token Embedded in Request URL
- Content
View full analysis
Vulnerability Details
File Location:
scripts/website_phone_number_finder_actor.py, lines 173-185
Vulnerability Type: Credential exposure through URL query parameters
Risk Level: MediumVulnerable Code
python def run_actor(token: str, actor_id: str, payload: dict[str, Any], timeout_sec: int, budget_usd: float | None) -> dict[str, Any]: params: dict[str, str | int | float] = { "token": token, "timeout": timeout_sec, "clean": "true", } if budget_usd is not None: if budget_usd <= 0: raise SkillError("--budget-usd must be > 0.") params["maxTotalChargeUsd"] = budget_usd actor_path = urllib.parse.quote(actor_id, safe="") url = f"https://api.apify.com/v2/acts/{actor_path}/run-sync-get-dataset-items?{urllib.parse.urlencode(params)}"Technical Analysis
The Apify API token is inserted into the request URL as the
tokenquery parameter. Although HTTPS encrypts the request in transit, URLs are frequently captured by local debugging tools, reverse proxies, HTTP monitoring systems, telemetry platforms, exception reports, and infrastructure access logs.Query-string authentication therefore increases the likelihood that the credential will be retained outside the process's intended security boundary. Anyone who obtains a complete logged URL can extract and reuse the token.
The outbound request itself is necessary for the Skill's declared hosted Apify workflow, and no undisclosed destination was identified. The vulnerability concerns the authentication transport mechanism rather than the legitimacy of the network request.
Attack Path
- A user runs the Skill with a valid Apify token.
- The runner constructs a URL containing
token=<credential>. - A proxy, debugger, monitoring agent, telemetry integration, or verbose network log records the complete URL.
- An attacker with access to that record extrac ...[truncated 558 chars]
- Remediation
View remediation
Remediation Suggestions
-
Authenticate through an HTTP authorization header instead of a query parameter where supported:
python request = urllib.request.Request( url, data=json.dumps(payload).encode("utf-8"), headers={ "Content-Type": "application/json", "Authorization": f"Bearer {token}", }, method="POST", ) -
Keep non-secret options such as timeout and budget in the query string, but remove
token. -
Redact authentication values from exceptions, diagnostics, and request logging.
-
Use a narrowly scoped Apify token where the platform supports token scoping.
-
Rotate any token that may already have appeared in URL or proxy logs.
-
