T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/tellermcp-server/src/client.ts:71
- Finding
- Unvalidated Remote Transaction Calldata Exposed as Ready-to-Submit Transactions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tellermcp-server/src/client.ts:71-132`; related exposure in `scripts/tellermcp-server/src/index.ts:143-180, 204-227` **Vulnerability Type**: Insufficient validation of security-sensitive remote API responses **Risk Level**: High ### Vulnerable Code ```ts getBorrowTransactions(params: { walletAddress: string; collateralTokenAddress: string; chainId: number; poolAddress: string; collateralAmount: string; principalAmount: string; loanDuration?: number; }): Promise<BorrowTransactionsResponse> { return this.request<BorrowTransactionsResponse>('/borrow-tx', { walletAddress: params.walletAddress, collateralTokenAddress: params.collateralTokenAddress, chainId: params.chainId, poolAddress: params.poolAddress, collateralAmount: params.collateralAmount, principalAmount: params.principalAmount, loanDuration: params.loanDuration }); } getLoans(params: { walletAddress: string; chainId: number }): Promise<LoansResponse> { return this.request<LoansResponse>('/loans/get-all', { walletAddress: params.walletAddress, chainId: params.chainId }); } getRepayTransactions(params: { bidId: number; chainId: number; walletAddress: string; amount?: string }): Promise<RepayTransactionsResponse> { return this.request<RepayTransactionsResponse>('/loans/repay-tx', { bidId: params.bidId, chainId: params.chainId, walletAddress: params.walletAddress, amount: params.amount }); } private async request<T>(path: string, query?: Record<string, string | number | boolean | undefined>): Promise<T> { const url = new URL(path, this.baseUrl); if (query) { for (const [key, value] of Object.entries(query)) { if (value === undefined || value === null || value === '') continue; url.searchParams.set(key, String(value)); } } const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), this.timeoutMs); t ...[truncated 4710 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Apply strict runtime response validation** - Define strict Zod schemas for borrow and repayment transaction responses. - Reject missing, malformed, additional, or incorrectly typed fields. - Enforce Ethereum address and hexadecimal calldata formats. - Limit transaction counts and response sizes. 2. **Verify transaction semantics** - Maintain an allowlist of Teller contracts for each supported chain. - Verify that every `to` address belongs to the selected chain and expected Teller deployment. - Decode calldata and allow only expected function selectors. - Confirm that approval spenders, tokens, recipients, loan IDs, pool addresses, and amounts match the original request. - Reject unexpected native-currency values and unrelated contract calls. - Apply conservative approval limits rather than accepting arbitrary or unlimited approvals. 3. **Restrict API origins** - Require HTTPS outside explicit local-development mode. - Allowlist trusted production hostnames. - Reject URLs containing credentials and unapproved ports or protocols. - Treat changes to `TELLER_API_BASE_URL` as security-sensitive configuration. 4. **Require informed transaction confirmation** - Decode and display each transaction’s destination, method, token, spender, amount, and native value. - Require explicit human confirmation before any signature or broadcast. - Clearly label API-generated calldata as untrusted until locally verified. - Remove documentation stating that remote results should be used directly. 5. **Strengthen request validation** - Require amount strings to match a decimal base-unit format such as `^(0|[1-9][0-9]*)$`. - Enforce nonzero and protocol-appropriate upper bounds. - Validate supported chain IDs and reasonable loan-duration limits. 6. **Fail closed** - If contract metadata, selector decoding, chain information, or response validation cannot be completed, do not re ...[truncated 48 chars]
