mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-01 19:25:10 +02:00
fix: Codex filesystem boundary — prevent skill-file prompt injection (v0.12.10.0) (#570)
* fix: add filesystem boundary to all codex prompts Codex CLI can read files outside the repo root despite -s read-only. It discovers ~/.claude/skills/ and ~/.agents/skills/, treats SKILL.md files as instructions, and executes preamble scripts instead of reviewing code. Fix: prepend a boundary instruction to all 11 codex exec/review callsites across codex/SKILL.md.tmpl (3), autoplan/ SKILL.md.tmpl (3), and scripts/resolvers/review.ts (5). Add rabbit- hole detection rule and 5 regression tests. * chore: bump version and changelog (v0.12.10.0) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1058,6 +1058,67 @@ describe('CODEX_SECOND_OPINION resolver', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// --- Codex filesystem boundary tests ---
|
||||
|
||||
describe('Codex filesystem boundary', () => {
|
||||
// Skills that call codex exec/review and should contain boundary text
|
||||
const CODEX_CALLING_SKILLS = [
|
||||
'codex', // /codex skill — 3 modes
|
||||
'autoplan', // /autoplan — CEO/design/eng voices
|
||||
'review', // /review — adversarial step resolver
|
||||
'ship', // /ship — adversarial step resolver
|
||||
'plan-eng-review', // outside voice resolver
|
||||
'plan-ceo-review', // outside voice resolver
|
||||
'office-hours', // second opinion resolver
|
||||
];
|
||||
|
||||
const BOUNDARY_MARKER = 'Do NOT read or execute any';
|
||||
|
||||
test('boundary instruction appears in all skills that call codex', () => {
|
||||
for (const skill of CODEX_CALLING_SKILLS) {
|
||||
const content = fs.readFileSync(path.join(ROOT, skill, 'SKILL.md'), 'utf-8');
|
||||
expect(content).toContain(BOUNDARY_MARKER);
|
||||
}
|
||||
});
|
||||
|
||||
test('codex skill has Filesystem Boundary section', () => {
|
||||
const content = fs.readFileSync(path.join(ROOT, 'codex', 'SKILL.md'), 'utf-8');
|
||||
expect(content).toContain('## Filesystem Boundary');
|
||||
expect(content).toContain('skill definitions meant for a different AI system');
|
||||
});
|
||||
|
||||
test('codex skill has rabbit-hole detection rule', () => {
|
||||
const content = fs.readFileSync(path.join(ROOT, 'codex', 'SKILL.md'), 'utf-8');
|
||||
expect(content).toContain('Detect skill-file rabbit holes');
|
||||
expect(content).toContain('gstack-update-check');
|
||||
expect(content).toContain('Consider retrying');
|
||||
});
|
||||
|
||||
test('review.ts CODEX_BOUNDARY constant is interpolated into resolver output', () => {
|
||||
// The adversarial step resolver should include boundary text in codex exec prompts
|
||||
const reviewContent = fs.readFileSync(path.join(ROOT, 'review', 'SKILL.md'), 'utf-8');
|
||||
// Boundary should appear near codex exec invocations
|
||||
const boundaryIdx = reviewContent.indexOf(BOUNDARY_MARKER);
|
||||
const codexExecIdx = reviewContent.indexOf('codex exec');
|
||||
// Both must exist and boundary must come before a codex exec call
|
||||
expect(boundaryIdx).toBeGreaterThan(-1);
|
||||
expect(codexExecIdx).toBeGreaterThan(-1);
|
||||
});
|
||||
|
||||
test('autoplan boundary text avoids host-specific paths for cross-host compatibility', () => {
|
||||
const content = fs.readFileSync(path.join(ROOT, 'autoplan', 'SKILL.md.tmpl'), 'utf-8');
|
||||
// autoplan template uses generic 'skills/gstack' pattern instead of host-specific
|
||||
// paths like ~/.claude/ or .agents/skills (which break Codex/Claude output tests)
|
||||
const boundaryStart = content.indexOf('Filesystem Boundary');
|
||||
const boundaryEnd = content.indexOf('---', boundaryStart + 1);
|
||||
const boundarySection = content.slice(boundaryStart, boundaryEnd);
|
||||
expect(boundarySection).not.toContain('~/.claude/');
|
||||
expect(boundarySection).not.toContain('.agents/skills');
|
||||
expect(boundarySection).toContain('skills/gstack');
|
||||
expect(boundarySection).toContain(BOUNDARY_MARKER);
|
||||
});
|
||||
});
|
||||
|
||||
// --- {{BENEFITS_FROM}} resolver tests ---
|
||||
|
||||
describe('BENEFITS_FROM resolver', () => {
|
||||
|
||||
Reference in New Issue
Block a user