fix: security hardening across SDK, CLI, and MCP#2
fix: security hardening across SDK, CLI, and MCP#2Hovessian wants to merge 1 commit intofetchai:mainfrom
Conversation
- MCP agentverse: validate agentFile path is within cwd (path traversal) - MCP scaffold: validate outputDir is within cwd for both scaffoldAgent and scaffoldSwarm - SDK handoff: validate Ethereum address format in generateTradeLink - SDK client: cap Retry-After wait to 30s to prevent unbounded sleep - CLI tokenize: validate --image URL scheme is HTTP/HTTPS (SSRF prevention) Addresses: fetchai/launchpadDAO#84, #85, #87, #89, #90 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| const waitMs = retryAfter | ||
| ? Math.min(parseInt(retryAfter, 10) * 1000, MAX_RETRY_WAIT_MS) | ||
| : delayMs; |
There was a problem hiding this comment.
Bug: parseInt on a non-numeric Retry-After header returns NaN, causing sleep(NaN) which results in an immediate retry instead of waiting.
Severity: MEDIUM
Suggested Fix
Validate the result of parseInt(retryAfter, 10) before using it. If the result is NaN, the logic should fall back to the default exponential backoff delay (delayMs) instead of using the invalid value. A check like !isNaN(parsedRetryAfter) should be added.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/sdk/src/client.ts#L161-L163
Potential issue: The code calculates `waitMs` using `parseInt(retryAfter, 10)`. If the
`Retry-After` header contains a non-numeric value, such as an HTTP-date string,
`parseInt` returns `NaN`. This `NaN` value propagates through the `Math.min`
calculation, resulting in a call to `sleep(NaN)`. The underlying `setTimeout` treats
`NaN` as a 0ms delay, causing the client to bypass the intended rate-limiting and enter
a tight retry loop. This can lead to client-side resource exhaustion and excessive
requests to the server when a malformed header is received.
Did we get this right? 👍 / 👎 to inform future reviews.
|
Closing — all 5 security fixes are already on main with equivalent or better implementations (extracted helper functions, stricter HTTPS-only policy for image URLs). Thanks for the thorough security audit; the issues identified were valid and important. |
Summary
agentFilepath is withinprocess.cwd()to prevent arbitrary file reads via path traversaloutputDiris withinprocess.cwd()for bothscaffoldAgentandscaffoldSwarmto prevent arbitrary file writes/^0x[a-fA-F0-9]{40}$/) ingenerateTradeLinkto prevent URL injectionRetry-Afterheader wait to 30 seconds to prevent a malicious server from stalling the client indefinitely--imageURL scheme is HTTP/HTTPS to prevent SSRF viafile://or other protocolsIssue #86 (default URL points to staging) is already fixed in
urls.ts— production is the default whenAGENT_LAUNCH_ENVis not set todev.Test plan
deploy_to_agentverserejects paths outside cwd (e.g.,../../etc/passwd)scaffold_agent/scaffold_swarmreject outputDir outside cwdgenerateTradeLinkthrows on malformed addressestokenize --image file:///etc/passwdis rejectedAddresses: fetchai/launchpadDAO#84, fetchai/launchpadDAO#85, fetchai/launchpadDAO#87, fetchai/launchpadDAO#89, fetchai/launchpadDAO#90
🤖 Generated with Claude Code