T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/register_onchain.py:121
- Finding
- Configurable ACN API Origin Can Receive Long-Lived Bearer Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/register_onchain.py:121-157, 162-166, 262-266`; related configuration instructions in `SKILL.md:53, 101-102` **Vulnerability Type**: Unvalidated credential destination **Risk Level**: High ### Complete Code Snippet ```python async def _get_agent_id(acn_url: str, api_key: str) -> str: """Look up the ACN agent ID via /api/v1/agents/me using the API key.""" import httpx async with httpx.AsyncClient() as client: resp = await client.get( f"{acn_url}/api/v1/agents/me", headers={"Authorization": f"Bearer {api_key}"}, timeout=15, ) resp.raise_for_status() data = resp.json() agent_id: str = data.get("agent_id") or data.get("id") or "" if not agent_id: raise RuntimeError(f"Could not determine agent_id from /me response: {data}") return agent_id async def _bind_to_acn( acn_url: str, api_key: str, agent_id: str, token_id: int, chain: str, tx_hash: str, ) -> None: """POST /api/v1/onchain/agents/{agent_id}/bind to register the binding in ACN.""" import httpx async with httpx.AsyncClient() as client: resp = await client.post( f"{acn_url}/api/v1/onchain/agents/{agent_id}/bind", json={"token_id": token_id, "chain": chain, "tx_hash": tx_hash}, headers={"Authorization": f"Bearer {api_key}"}, timeout=30, ) resp.raise_for_status() ``` ```python acn_url = args.acn_url.rstrip("/") api_key = args.acn_api_key ``` ```python parser.add_argument( "--acn-url", default=os.getenv("ACN_API_URL", "https://api.acnlabs.dev"), help="ACN server base URL", ) ``` The broader Skill also permits arbitrary configured origins: ```text Precedence: --base-url → --region → ACN_BASE_URL → ~/.acn/config.json → global. ``` ```text acn join --base-url <origin> ``` ### Technical Analysis The script obtains ...[truncated 2288 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse the configured URL with a strict URL parser before any authenticated request. 2. Require `https` for all non-loopback destinations. 3. Allowlist the documented production hosts by default: - `api.acnlabs.dev` - `acn.acnlabs.cn` 4. Treat custom/self-hosted origins as an advanced mode requiring explicit user confirmation before transmitting a credential. 5. Reject embedded usernames/passwords, fragments, malformed hosts, and unexpected ports. 6. Instantiate the HTTP client with redirects disabled and reject any response that attempts to move the request to another origin. 7. Store credentials per origin so a credential issued by one ACN deployment cannot automatically be sent to another. 8. Display the normalized destination hostname before the first credential-bearing request, without displaying the credential. 9. Add tests covering HTTP downgrade attempts, deceptive subdomains, user-information URLs, custom ports, and poisoned environment variables. ]]>
