From 72959620494191da95fce854abd943f9d0000213 Mon Sep 17 00:00:00 2001 From: jingyiama Date: Sat, 23 May 2026 13:50:11 -0400 Subject: [PATCH] Fix command injection in senso CLI invocations Switch from execSync with interpolated shell strings to execFileSync with argv arrays. JSON.stringify does not escape single quotes, so untrusted search-result content reaching publishReceipt could break out of the shell-quoted --data argument and execute arbitrary commands. Co-Authored-By: Claude Opus 4.7 (1M context) --- publish.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/publish.js b/publish.js index 2153bd8..0b810c0 100644 --- a/publish.js +++ b/publish.js @@ -1,4 +1,4 @@ -const { execSync } = require('child_process'); +const { execFileSync } = require('child_process'); async function publishReceipt({ query, selectedResult, price, txHash, sourceUrl, searchResults }) { const apiKey = process.env.SENSO_API_KEY; @@ -10,7 +10,7 @@ async function publishReceipt({ query, selectedResult, price, txHash, sourceUrl, // Create a Senso prompt tied to this purchase so we have a geo_question_id to publish against const promptJson = senso( - `prompts create --data '${JSON.stringify({ question_text: questionText, type: 'decision' })}'`, + ['prompts', 'create', '--data', JSON.stringify({ question_text: questionText, type: 'decision' })], apiKey ); const promptId = promptJson.prompt_id ?? promptJson.id; @@ -18,12 +18,12 @@ async function publishReceipt({ query, selectedResult, price, txHash, sourceUrl, // Publish the receipt as a citeable on cited.md const publishJson = senso( - `engine publish --data '${JSON.stringify({ + ['engine', 'publish', '--data', JSON.stringify({ geo_question_id: promptId, raw_markdown: markdown, seo_title: seoTitle, summary: `Shop3 autonomously purchased ${selectedResult} for ${price}. Tx: ${txHash}`, - })}'`, + })], apiKey ); @@ -34,7 +34,7 @@ async function publishReceipt({ query, selectedResult, price, txHash, sourceUrl, // Run a senso CLI command and return parsed JSON output function senso(args, apiKey) { - const result = execSync(`senso ${args} --output json --quiet`, { + const result = execFileSync('senso', [...args, '--output', 'json', '--quiet'], { env: { ...process.env, SENSO_API_KEY: apiKey }, encoding: 'utf8', });