karajan-code 1.25.1 → 1.25.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karajan-code",
3
- "version": "1.25.1",
3
+ "version": "1.25.2",
4
4
  "description": "Local multi-agent coding orchestrator with TDD, SonarQube, and code review pipeline",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0",
@@ -823,10 +823,43 @@ function handleRoles(a) {
823
823
  return runKjCommand({ command: "roles", commandArgs, options: a });
824
824
  }
825
825
 
826
+ const RESUME_MAX_ANSWER_LENGTH = 500;
827
+ const RESUME_INJECTION_PATTERNS = [
828
+ /ignore\s+(previous|all|above)\s+(instructions|rules|prompts)/i,
829
+ /you\s+are\s+now/i,
830
+ /new\s+instructions?:/i,
831
+ /override\s+(all|security|guardrails|rules)/i,
832
+ /skip\s+(all\s+)?(review|test|sonar|security|solomon|guard)s?\b/i,
833
+ /disable\s+(tdd|review|test|sonar|security)\b/i,
834
+ /set\s+(status|approved|verdict)\s*(=|to|:)/i,
835
+ /force\s+(approve|merge|push|commit)\b/i,
836
+ ];
837
+
838
+ export function validateResumeAnswer(answer) {
839
+ if (answer == null || answer === "") return { valid: true, sanitized: answer ?? null };
840
+ if (typeof answer !== "string") return { valid: true, sanitized: String(answer) };
841
+ if (answer.length > RESUME_MAX_ANSWER_LENGTH) {
842
+ return { valid: false, reason: `Answer too long (${answer.length} chars, max ${RESUME_MAX_ANSWER_LENGTH})` };
843
+ }
844
+ for (const pattern of RESUME_INJECTION_PATTERNS) {
845
+ if (pattern.test(answer)) {
846
+ return { valid: false, reason: "Answer rejected: matches guardrail bypass pattern" };
847
+ }
848
+ }
849
+ return { valid: true, sanitized: answer.trim() };
850
+ }
851
+
826
852
  async function handleResume(a, server, extra) {
827
853
  if (!a.sessionId) {
828
854
  return failPayload("Missing required field: sessionId");
829
855
  }
856
+ if (a.answer) {
857
+ const validation = validateResumeAnswer(a.answer);
858
+ if (!validation.valid) {
859
+ return failPayload(`Resume answer rejected: ${validation.reason}`);
860
+ }
861
+ a.answer = validation.sanitized;
862
+ }
830
863
  applySessionOverrides(a, ["coder", "reviewer", "tester", "security", "solomon", "enableTester", "enableSecurity", "enableImpeccable"]);
831
864
  return handleResumeDirect(a, server, extra);
832
865
  }