fix(security): emailsFromHeader fail-closed, domain_auditor-Block, Manticore-Tabellenvalidierung

- emailsFromHeader gibt bei Parse-Fehler nil zurück (fail-closed) statt raw-Header-String;
  verhindert Authorization-Bypass via malformiertem From-Header
- mailBelongsToUser: strings.Contains-Fallback entfernt (war dead code nach dem fix-closed-Fix)
- handleSearch: domain_auditor ohne TenantID wird mit 403 abgewiesen, bevor der globale Index
  abgefragt wird
- manticoreTableName: Regex-Validierung ^emails_(global|tenant_\d+)$ mit panic bei Abweichung

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-04-04 02:01:50 +02:00
parent 896f8dceb9
commit e1f25f2287
2 changed files with 28 additions and 12 deletions
+15 -2
View File
@@ -4,6 +4,7 @@ import (
"database/sql"
"fmt"
"hash/fnv"
"regexp"
"strings"
"sync"
"time"
@@ -11,6 +12,10 @@ import (
_ "github.com/go-sql-driver/mysql"
)
// validTableName guards against SQL injection via table name interpolation.
// Only emails_global and emails_tenant_<digits> are valid Manticore RT tables.
var validTableName = regexp.MustCompile(`^emails_(global|tenant_\d+)$`)
// manticoreIndex implements Indexer against a single Manticore RT table.
type manticoreIndex struct {
db *sql.DB
@@ -304,11 +309,19 @@ func hashMailID(id string) uint64 {
// manticoreTableName returns the RT table name for a given tenant.
// nil / 0 → emails_global, otherwise emails_tenant_<id>.
// Panics if the resulting name does not match validTableName — this would
// indicate a programming error, not a runtime condition.
func manticoreTableName(tenantID *int64) string {
var name string
if tenantID == nil || *tenantID == 0 {
return "emails_global"
name = "emails_global"
} else {
name = fmt.Sprintf("emails_tenant_%d", *tenantID)
}
return fmt.Sprintf("emails_tenant_%d", *tenantID)
if !validTableName.MatchString(name) {
panic(fmt.Sprintf("manticore: invalid table name: %q", name))
}
return name
}
// escapeManticoreMatch escapes characters that have special meaning in