Root cause
Injection & unsafe execution introduced
The AI-assisted change below is where the vulnerable behavior appears.
How AI contributed: Direct introductionPublished Jun 22, 2026 in
actualbudget/actual
Provisional finding. Full causal and release verification remains incomplete.
An AI-assisted CLI serializer exported stored budget strings with CSV syntax escaping but without neutralizing spreadsheet formulas. A person able to write data used by a victim could influence exported cells if the victim chose CSV and imported it with formula evaluation enabled. This does not establish CLI execution, automatic disclosure, or universal spreadsheet behavior.
Root cause
The AI-assisted change below is where the vulnerable behavior appears.
Fix
The repair combines type-aware formula neutralization with carriage-return quoting. Source releases 26.4.0, 26.5.0, 26.5.1 and 26.5.2 were checked as affected, and the repaired source and published CLI 26.6.0 package were verified.
Case facts
@@ -0,0 +57,26 @@+ }++ if (data.length === 0) {+ return '';+ }++ const keys = Object.keys(data[0] as Record<string, unknown>);+ const header = keys.map(k => escapeCsv(k)).join(',');+ const rows = data.map(row => {+ const r = row as Record<string, unknown>;+ return keys.map(k => escapeCsv(String(r[k] ?? ''))).join(',');+ });++ return [header, ...rows].join('\n');+}++function escapeCsv(value: string): string {+ if (value.includes(',') || value.includes('"') || value.includes('\n')) {+ return '"' + value.replace(/"/g, '""') + '"';+ }+ return value;+}++export function printOutput(data: unknown, format: OutputFormat = 'json') {+ process.stdout.write(formatOutput(data, format) + '\n');+}@@ -89,10 +91,24 @@ const header = keys.map(k => escapeCsv(k)).join(','); const rows = data.map(row => { const r = row as Record<string, unknown>;- return keys.map(k => escapeCsv(formatCellValue(k, r[k]))).join(',');+ return keys.map(k => escapeCsvCell(formatCellValue(k, r[k]))).join(','); }); return [header, ...rows].join('\n');+}++// Characters that trigger formula evaluation in Excel / LibreOffice Calc /+// Google Sheets when they appear at the start of a cell. Prefixing such a+// value with a single quote neutralizes the formula (OWASP-recommended;+// CWE-1236). We skip neutralization for values that originated as numbers,+// since negative amounts like "-25.00" would otherwise be quoted as text.+const FORMULA_TRIGGERS = /^[=+\-@\t\r]/;++function escapeCsvCell({ value, isNumeric }: FormattedCell): string {+ if (!isNumeric && FORMULA_TRIGGERS.test(value)) {+ value = "'" + value;+ }+ return escapeCsv(value); } function escapeCsv(value: string): string {@@ -106,7 +106,12 @@ } function escapeCsv(value: string): string {- if (value.includes(',') || value.includes('"') || value.includes('\n')) {+ if (+ value.includes(',') ||+ value.includes('"') ||+ value.includes('\n') ||+ value.includes('\r')+ ) { return '"' + value.replace(/"/g, '""') + '"'; } return value;AI-assisted change 7545a6392b8415d9a73f20817646a5a22b1044f2295628dcdd10379400cfaa07 · Fix 0d1110506b53e78cd734da22bd3c5251bdb7900789ad0489a1a45e117c18a653