diff --git a/bin/gstack-learnings-log b/bin/gstack-learnings-log index ad27091e5..ff544237d 100755 --- a/bin/gstack-learnings-log +++ b/bin/gstack-learnings-log @@ -15,6 +15,7 @@ INPUT="$1" # Validate and sanitize input VALIDATED=$(printf '%s' "$INPUT" | bun -e " +import { hasInjection } from '$SCRIPT_DIR/../lib/jsonl-store.ts'; const raw = await Bun.stdin.text(); let j; try { j = JSON.parse(raw); } catch { process.stderr.write('gstack-learnings-log: invalid JSON, skipping\n'); process.exit(1); } @@ -47,27 +48,11 @@ if (j.source && !ALLOWED_SOURCES.includes(j.source)) { process.exit(1); } -// Content sanitization: strip instruction-like patterns from insight field -// These patterns could be used for prompt injection when learnings are loaded into agent context -if (j.insight) { - const INJECTION_PATTERNS = [ - /ignore\s+(all\s+)?previous\s+(instructions|context|rules)/i, - /you\s+are\s+now\s+/i, - /always\s+output\s+no\s+findings/i, - /skip\s+(all\s+)?(security|review|checks)/i, - /override[:\s]/i, - /\bsystem\s*:/i, - /\bassistant\s*:/i, - /\buser\s*:/i, - /do\s+not\s+(report|flag|mention)/i, - /approve\s+(all|every|this)/i, - ]; - for (const pat of INJECTION_PATTERNS) { - if (pat.test(j.insight)) { - process.stderr.write('gstack-learnings-log: insight contains suspicious instruction-like content, rejected\n'); - process.exit(1); - } - } +// Content sanitization: shared injection patterns (lib/jsonl-store.ts, D2A) — +// one audited list across learnings + decisions, no drift. +if (j.insight && hasInjection(j.insight)) { + process.stderr.write('gstack-learnings-log: insight contains suspicious instruction-like content, rejected\n'); + process.exit(1); } // Inject timestamp if not present