T09 · Insecure Skill Coding Practices
- Location
scripts/prana_skill_client.py:27- Finding
Arbitrary API endpoint can receive reusable credentials and sensitive portfolio data
- Content
View full analysis
Vulnerability Details
File Location:
scripts/prana_skill_client.py, lines 27, 128–133, 259–269, and 299
Vulnerability Type: Unrestricted destination for authenticated network requests
Risk Level: HighVulnerable Code
python DEFAULT_PRANA_BASE = os.environ.get( "NEXT_PUBLIC_URL", "https://suna-dev.ebonex.io", )python def _headers_x_api_key(public_key: str, secret_key: str) -> dict[str, str]: """Claw interface requirement: x-api-key is public_key:secret_key.""" return { "Content-Type": "application/json", "x-api-key": f"{public_key}:{secret_key}", }python url = base_url.rstrip("/") + "/api/claw/agent-run" body = { "skill_key": skill_key, "question": content, "thread_id": thread_id or "", "request_id": request_id, } data = json.dumps(body, ensure_ascii=False).encode("utf-8") req = urllib.request.Request( url, data=data, method="POST", headers=_headers_x_api_key(public_key, secret_key), )python parser.add_argument( "--base-url", "-b", default=DEFAULT_PRANA_BASE, help="Prana API root address", )Technical Analysis
The client allows its remote API base URL to be selected through either the
NEXT_PUBLIC_URLenvironment variable or the--base-urlcommand-line argument. It then sends the reusablepublic_key:secret_keycredential in thex-api-keyheader and transmits the user's message in the request body.No validation restricts the destination to an approved Prana hostname, requires HTTPS, rejects embedded URL credentials, or prevents unusual ports and redirect-based origin changes. Consequently, destination selection crosses a security boundary: an untrusted launcher, wrapper, inherited environment, or copied command can cause locally loaded credentials and portfolio information to be sent to an attacker-controlled server.
The result-recovery calls at lines 278, 283, and 290 are not independently malicious. Reusing ...[truncated 2506 chars]
- Remediation
View remediation
Remediation Suggestions
-
Require HTTPS
- Parse the URL with
urllib.parse.urlsplit. - Reject all schemes except
https. - Reject missing hostnames, URL user information, fragments, and unsupported ports.
- Parse the URL with
-
Allowlist trusted API origins
- Maintain an explicit list of approved Prana hostnames.
- Compare normalized hostnames exactly; do not use suffix checks vulnerable to names such as
trusted.example.attacker.test. - Prefer removing
--base-urlfrom production releases if arbitrary endpoints are unnecessary.
-
Protect custom endpoint overrides
- If development endpoints are required, gate them behind an explicit development mode.
- Require interactive confirmation before sending credentials to a nonstandard origin.
- Display the normalized destination without revealing credentials.
-
Control redirects
- Disable redirects for authenticated requests or validate every redirect target before forwarding the
x-api-keyheader. - Never forward authentication headers across origins.
- Disable redirects for authenticated requests or validate every redirect target before forwarding the
-
Reduce credential exposure
- Use short-lived, narrowly scoped tokens instead of long-lived
public_key:secret_keycredentials where supported. - Scope keys to only the required skill and API routes.
- Add key rotation and revocation guidance for suspected exposure.
- Use short-lived, narrowly scoped tokens instead of long-lived
-
Harden credential storage
- Prefer environment injection or an operating-system secret store.
- If files must be supported, require restrictive permissions such as owner read/write only.
- Ensure credential files are excluded from version control.
-
Add security tests
- Verify rejection of
http://, attacker-controlled hosts, embedded user information, malformed URLs, unexpected ports, and cross-origin redirects. - Verify that authentication headers are sent only to explicitly approved HTTPS origins.
- Verify rejection of
-
