codeburn/tests/security/menubar-injection.test.ts
Ninym 71461fb352 test(security): add failing test for MEDIUM-2 menubar injection
Three cases (pipe-in-model, ANSI-in-model, pipe-in-category) reproduce
the audit's SwiftBar directive-separator attack. Tests fail against
current menubar.ts -- Task 13 will close with an allowlist sanitizer.
2026-04-17 08:32:20 +02:00

47 lines
1.4 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { renderMenubarFormat, type PeriodData } from '../../src/menubar.js'
const ESC = '\u001b'
function period(name: string): PeriodData {
return {
label: 'x',
cost: 0.01,
calls: 1,
inputTokens: 1,
outputTokens: 1,
cacheReadTokens: 0,
cacheWriteTokens: 0,
categories: [{ name, cost: 0.01, turns: 1, editTurns: 0, oneShotTurns: 1 }],
models: [{ name, cost: 0.01, calls: 1 }],
}
}
function linesWithToken(output: string, token: string): string[] {
return output.split('\n').filter(l => l.includes(token))
}
describe('MEDIUM-2 menubar directive separator injection', () => {
it('strips pipe separators from model names', () => {
const p = period('foo | href=https://attacker.example/pwn')
const out = renderMenubarFormat(p, p, p, p)
for (const line of linesWithToken(out, 'foo')) {
expect(line.split('|').length).toBeLessThanOrEqual(2)
}
})
it('strips ANSI escapes from model names', () => {
const p = period(`foo${ESC}[31mMODEL${ESC}[0m`)
const out = renderMenubarFormat(p, p, p, p)
expect(out).not.toContain(ESC)
})
it('strips pipe separators from category names', () => {
const p = period('cat | color=red')
const out = renderMenubarFormat(p, p, p, p)
for (const line of linesWithToken(out, 'cat')) {
expect(line.split('|').length).toBeLessThanOrEqual(2)
}
})
})