Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/handlers/identity-neutralize.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,26 @@ export function neutralizeClientIdentity(text, env = process.env, opts = {}) {
/You are ([A-Z][\w.-]*), a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns,? and best practices\./g,
'You are $1, a software engineer.',
);
// (a6-grok) Grok / xAI self-identification (2026-07-16, live-confirmed to
// trip Devin's content policy → permission_denied). Grok CLI opens with
// "You are Grok 4.5 released by xAI. You are an interactive CLI tool that
// helps users with software engineering tasks." A/B on the live upstream:
// this exact line is what triggers the block — the same request with a
// generic assistant line passes. Match the full "You are Grok ... released
// by xAI" form and the bare noun phrase, any Grok version digit.
out = out.replace(
/You are Grok[\w .-]* released by xAI\.?/gi,
'You are an AI coding assistant.',
);
out = out.replace(
/\bGrok[\w .-]* released by xAI\.?/gi,
'an AI coding assistant.',
);
// (a6-grok2) Grok's executing_actions_with_care safety paragraph — a
// competitor-specific safety/policy framing that rides in the prompt body
// and has been observed in the same blocked request. Strip the whole
// <executing_actions_with_care>...</executing_actions_with_care> block.
out = out.replace(/<executing_actions_with_care>[\s\S]*?<\/executing_actions_with_care>/gi, '');
// (a6) SPECULATIVE / HYPOTHESIS-ONLY (2026-07-15), DEFAULT-OFF. Unlike a1-a5
// which are live-bisected confirmed triggers, this OBJECTIVE boast sentence is
// only SUSPECTED to be in the same content-policy trigger family — NOT verified,
Expand Down
67 changes: 67 additions & 0 deletions test/client-identity-neutralize.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,73 @@ describe('neutralizeClientIdentity', () => {
});
});

// 2026-07-16 (a6-grok/a6-grok2): Grok CLI's system prompt opens with "You are
// Grok 4.5 released by xAI. You are an interactive CLI tool that helps users
// with software engineering tasks." Live A/B on the Devin upstream proved that
// exact self-ID line trips the content policy (permission_denied); the same
// request with a generic assistant line passes. The competitor-specific
// <executing_actions_with_care> safety paragraph rides in the same blocked
// prompt body and is stripped whole. Both rules are unconditional like a1-a5,
// gated only by the main WINDSURFAPI_NEUTRALIZE_CLIENT_ID switch (default on).
describe('neutralizeClientIdentity — Grok / xAI rules (a6-grok)', () => {
const GROK_ID = 'You are Grok 4.5 released by xAI.';

it('rewrites the exact Grok self-identification', () => {
const out = neutralizeClientIdentity(GROK_ID + ' You are an interactive CLI tool that helps users with software engineering tasks.');
assert.ok(!/Grok/.test(out), 'no Grok');
assert.ok(!/xAI/.test(out), 'no xAI');
assert.match(out, /^You are an AI coding assistant\./, 'opens with the generic identity line');
assert.match(out, /You are an interactive CLI tool that helps users with software engineering tasks\./, 'rest of prompt preserved');
});

it('neutralizes the bare noun phrase without the leading "You are"', () => {
const out = neutralizeClientIdentity('Note: Grok 4 released by xAI is running.');
assert.ok(!/Grok/.test(out), 'no Grok');
assert.ok(!/released by xAI/i.test(out), 'no xAI attribution');
assert.match(out, /an AI coding assistant\./, 'generic noun phrase substituted');
});

it('matches any Grok version variant (4.5.1, 3 mini, ...)', () => {
assert.equal(
neutralizeClientIdentity('You are Grok 4.5.1 released by xAI.'),
'You are an AI coding assistant.',
);
assert.equal(
neutralizeClientIdentity('You are Grok 3 mini released by xAI.'),
'You are an AI coding assistant.',
);
});

it('strips the <executing_actions_with_care> block entirely', () => {
const out = neutralizeClientIdentity('<executing_actions_with_care>foo bar</executing_actions_with_care>');
assert.equal(out, '', 'inline block fully removed');
});

it('strips a multiline <executing_actions_with_care> block and keeps surrounding text', () => {
const src = 'Before.\n<executing_actions_with_care>\nfoo bar\nDouble-check destructive commands before running them.\n</executing_actions_with_care>\nAfter.';
const out = neutralizeClientIdentity(src);
assert.ok(!/executing_actions_with_care/i.test(out), 'tags removed');
assert.ok(!/foo bar/.test(out), 'block content removed');
assert.ok(!/destructive commands/.test(out), 'multiline content removed');
assert.match(out, /Before\./, 'content before kept');
assert.match(out, /After\./, 'content after kept');
});

it('leaves unrelated mentions of "Grok" alone (no "released by xAI" attribution)', () => {
// Bare mentions are safe — only the xAI-attributed self-ID phrasing is rewritten.
const src = 'Use the Logstash grok filter. Grok patterns parse logs.';
assert.equal(neutralizeClientIdentity(src), src, 'unrelated text untouched');
const plainId = 'You are Grok, a helpful assistant.';
assert.equal(neutralizeClientIdentity(plainId), plainId, 'un-attributed identity line untouched');
});

it('the Grok neutralization respects the opt-out flag', () => {
process.env.WINDSURFAPI_NEUTRALIZE_CLIENT_ID = '0';
const src = GROK_ID + '\n<executing_actions_with_care>Take care.</executing_actions_with_care>';
assert.equal(neutralizeClientIdentity(src), src, 'opt-out leaves it verbatim');
});
});

// P2 — Claude Code compat layer: the ccActive gate on the opt-in (cc) block.
// Contract: a1-a5 stay UNCONDITIONAL (default 529 / content-policy defense for
// ALL clients); the (cc) block is opt-in and currently EMPTY, so activating it
Expand Down
Loading