Files

100 lines
2.1 KiB
Go
Raw Permalink Normal View History

package security
import (
"regexp"
"strings"
"unicode"
)
const (
// MaxCampaignPromptRunes caps custom campaign / brand AI prompts (prompt-injection surface).
MaxCampaignPromptRunes = 8000
// MaxBrandFieldRunes caps individual brand kit text fields.
MaxBrandFieldRunes = 2000
// MaxBrandListItems caps dos/donts/preferred_terms entries.
MaxBrandListItems = 40
// MaxBrandListItemRunes caps each list entry.
MaxBrandListItemRunes = 200
)
var injectPhrase = regexp.MustCompile(`(?i)(ignore\s+previous|system\s*:|assistant\s*:|<\s*/?\s*script)`)
// SanitizePrompt strips controls, soft-filters injection phrases, and truncates by runes.
func SanitizePrompt(s string, maxRunes int) string {
if maxRunes <= 0 {
maxRunes = MaxCampaignPromptRunes
}
s = stripControls(strings.TrimSpace(s))
s = injectPhrase.ReplaceAllString(s, "[filtered]")
return TruncateRunes(s, maxRunes)
}
// CapPromptLength reports whether s exceeds max (rune count).
func CapPromptLength(s string, maxRunes int) bool {
if maxRunes <= 0 {
maxRunes = MaxCampaignPromptRunes
}
n := 0
for range s {
n++
if n > maxRunes {
return true
}
}
return false
}
// SanitizeBrandList cleans and bounds a brand kit string list.
func SanitizeBrandList(in []string) []string {
if len(in) == 0 {
return []string{}
}
out := make([]string, 0, len(in))
seen := map[string]struct{}{}
for _, s := range in {
s = SanitizePrompt(s, MaxBrandListItemRunes)
if s == "" {
continue
}
key := strings.ToLower(s)
if _, ok := seen[key]; ok {
continue
}
seen[key] = struct{}{}
out = append(out, s)
if len(out) >= MaxBrandListItems {
break
}
}
return out
}
func stripControls(s string) string {
if s == "" {
return ""
}
var b strings.Builder
b.Grow(len(s))
for _, r := range s {
if r == '\n' || r == '\t' || unicode.IsPrint(r) {
b.WriteRune(r)
}
}
return b.String()
}
// TruncateRunes truncates s to at most max runes.
func TruncateRunes(s string, max int) string {
if max <= 0 {
return ""
}
n := 0
for i := range s {
if n == max {
return s[:i]
}
n++
}
return s
}