- Location
- src/archive.ts:99
- Finding
- Spreadsheet Formula Injection in CSV Export<![CDATA[
## Vulnerability Details
**File Location**: `src/archive.ts:99-117`
**Vulnerability Type**: CSV/spreadsheet formula injection
**Risk Level**: Medium
The corresponding compiled implementation is also present in `dist/archive.js:121-139`.
### Vulnerable Code
```typescript
} else if (format === 'csv') {
const exportFile = path.join(process.cwd(), `memory_export_${timestamp}.csv`);
const lines = ['id,content,tag,type,importance,timestamp,strength_score,strength_level'];
for (const memory of memories) {
const row = [
memory.id,
`"${memory.content.replace(/"/g, '""')}"`,
memory.tag || '',
memory.type || '',
memory.importance || '',
memory.timestamp,
memory.strength.score,
memory.strength.level,
].join(',');
lines.push(row);
}
fs.writeFileSync(exportFile, lines.join('\n'), 'utf-8');
printColored(`✓ Exported to ${exportFile}`, 'green');
```
### Technical Analysis
Memory content and tags can contain user-controlled text. The exporter doubles quotes in the content field, which addresses part of CSV structural escaping, but it does not neutralize spreadsheet formulas.
Spreadsheet applications may interpret a cell as a formula when its value begins with characters such as:
- `=`
- `+`
- `-`
- `@`
- Tab or carriage-return control characters in some applications
Enclosing a value in CSV double quotes does not necessarily prevent formula evaluation. Other string fields, including `tag` and `type`, are not consistently CSV-quoted and can also contain delimiters or formula-leading values.
For example, a stored memory whose content begins with a spreadsheet formula remains formula-capable in the exported CSV when opened in a compatible spreadsheet application.
### Attack Path
1. An attacker causes malicious formula-like text to be stored in a memory or tag.
2. The victim runs:
```bash
memory export --format=csv
```
3. The Skill writes the attacker-controlled text into the CSV wit
...[truncated 935 chars]
- Remediation
- <![CDATA[
## Remediation Suggestions
Apply a single defensive CSV-encoding function to every exported field. The function should:
1. Convert the value to text.
2. Detect formula-leading characters after any leading whitespace.
3. Prefix dangerous values with an apostrophe or another application-appropriate neutralization character.
4. Escape embedded double quotes.
5. Quote every string field consistently.
Example:
```typescript
function encodeCsvCell(value: unknown): string {
let text = String(value ?? '');
if (/^[\s]*[=+\-@]/.test(text) || /^[\t\r]/.test(text)) {
text = `'${text}`;
}
return `"${text.replace(/"/g, '""')}"`;
}
```
Use it for every field:
```typescript
const row = [
memory.id,
memory.content,
memory.tag,
memory.type,
memory.importance,
memory.timestamp,
memory.strength.score,
memory.strength.level,
].map(encodeCsvCell).join(',');
```
Also:
- Add tests for values beginning with `=`, `+`, `-`, `@`, tabs, carriage returns, commas, quotes, and newlines.
- Document that exported records may originate from untrusted users.
- Regenerate `dist/archive.js` after correcting the TypeScript source.
]]>