Batteries

Security (Sentinel)

Every Grit project ships with Sentinel -- a production-grade security intelligence suite that provides a Web Application Firewall, rate limiting, brute-force protection, anomaly detection, security headers, and a real-time threat dashboard. Security is not an afterthought.

What's Included

Sentinel mounts on your Gin router with a single call and provides the following out of the box:

Web Application Firewall

Detects SQL injection, XSS, path traversal, command injection, SSRF, XXE, and more

Rate Limiting

Per-IP, per-user, per-route, and global limits with sliding window strategy

Auth Shield

Brute-force protection with per-IP lockouts and credential stuffing detection

Security Headers

CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy

Anomaly Detection

Off-hours access, velocity anomalies, impossible travel, data exfiltration

IP Geolocation

Automatic geo-lookup for every request with country and city data

Threat Dashboard

Embedded React dashboard with real-time WebSocket updates at /sentinel/ui

Performance Monitoring

Per-route latency tracking with p50/p95/p99 metrics

Configuration

Sentinel is enabled by default in every Grit project. Configure it through your .env file:

.env
# Security — Sentinel WAF, rate limiting, threat detection
SENTINEL_ENABLED=true
SENTINEL_USERNAME=admin
SENTINEL_PASSWORD=sentinel
SENTINEL_SECRET_KEY=change-me-in-production
VariableDefaultDescription
SENTINEL_ENABLEDtrueSet to "false" to disable Sentinel entirely
SENTINEL_USERNAMEadminDashboard login username
SENTINEL_PASSWORDsentinelDashboard login password
SENTINEL_SECRET_KEYsentinel-secret...Secret for dashboard JWT sessions

How It Works

Sentinel is mounted in your routes.go Setup function, right after the global middleware (Logger, Recovery, CORS) and before any route registrations. This means every request passes through Sentinel's security middleware:

internal/routes/routes.go
// Mount Sentinel security suite
if cfg.SentinelEnabled {
sentinel.Mount(r, db, sentinel.Config{
Dashboard: sentinel.DashboardConfig{
Username: cfg.SentinelUsername,
Password: cfg.SentinelPassword,
SecretKey: cfg.SentinelSecretKey,
},
WAF: sentinel.WAFConfig{
Enabled: true,
Mode: sentinel.ModeLog,
},
RateLimit: sentinel.RateLimitConfig{
Enabled: true,
ByIP: &sentinel.Limit{Requests: 100, Window: 1 * time.Minute},
ByRoute: map[string]sentinel.Limit{
"/api/auth/login": {Requests: 5, Window: 15 * time.Minute},
"/api/auth/register": {Requests: 3, Window: 15 * time.Minute},
},
},
AuthShield: sentinel.AuthShieldConfig{
Enabled: true,
LoginRoute: "/api/auth/login",
},
Anomaly: sentinel.AnomalyConfig{
Enabled: true,
},
Geo: sentinel.GeoConfig{
Enabled: true,
},
})
}

The middleware execution order is: Auth Shield (intercepts login attempts) → WAF (inspects all input vectors) → Rate Limiter (enforces request limits) → Security Headers (injects response headers) → Performance Monitor (tracks latency).

Security Dashboard

Sentinel ships with an embedded React dashboard at /sentinel/ui. Log in with the username and password from your .env file (default: admin / sentinel).

The dashboard provides:

  • Threat feed -- real-time threat events via WebSocket with severity, type, and source IP
  • Threat actors -- automatic profiling with risk scores, attack types, and geolocation
  • Security score -- weighted score across 5 dimensions with actionable recommendations
  • Analytics -- attack trends, geographic distribution, top targeted routes
  • WAF rules -- view and configure rules, test payloads, add custom patterns
  • Rate limits -- view active limits and live counter states
  • IP management -- block/unblock IPs, view blocked list
  • Audit logs -- GORM-level CREATE/UPDATE/DELETE audit trail with before/after diffs
  • Performance -- per-route latency metrics (p50/p95/p99) and error rates
  • Compliance reports -- generate GDPR, PCI-DSS, and SOC2 reports

The dashboard is also embedded in the admin panel under System → Security for convenience.

WAF Modes

The Web Application Firewall has two modes:

ModeLogdefault

Detects and logs threats but does not block requests. Use during development and initial deployment to identify false positives before switching to block mode.

ModeBlockproduction

Detects threats and blocks malicious requests with a 403 response. Switch to this mode in production after verifying no false positives in log mode.

To switch modes, change sentinel.ModeLog to sentinel.ModeBlock in your routes.go. You can also toggle the mode at runtime from the dashboard.

The WAF detects the following attack types with configurable sensitivity per rule (off, low, medium, strict):

SQL Injection (basic, blind, stacked)
Cross-Site Scripting (XSS)
Path Traversal
Command Injection
Server-Side Request Forgery (SSRF)
XML External Entity (XXE)
Local File Inclusion (LFI)
Open Redirect

Rate Limiting

Grit configures sensible rate limits out of the box. You can customize them in routes.go:

internal/routes/routes.go
RateLimit: sentinel.RateLimitConfig{
Enabled: true,
ByIP: &sentinel.Limit{Requests: 100, Window: 1 * time.Minute},
ByRoute: map[string]sentinel.Limit{
"/api/auth/login": {Requests: 5, Window: 15 * time.Minute},
"/api/auth/register": {Requests: 3, Window: 15 * time.Minute},
"/api/uploads": {Requests: 10, Window: 1 * time.Minute},
},
// Optional: per-user and global limits
// ByUser: &sentinel.Limit{Requests: 200, Window: 1 * time.Minute},
// Global: &sentinel.Limit{Requests: 1000, Window: 1 * time.Minute},
Strategy: sentinel.SlidingWindow, // or FixedWindow, TokenBucket
},

Auth Shield

The auth shield protects your login endpoint from brute-force attacks. When enabled, it automatically tracks failed login attempts per IP address and locks out attackers after too many failures.

internal/routes/routes.go
AuthShield: sentinel.AuthShieldConfig{
Enabled: true,
LoginRoute: "/api/auth/login",
MaxFailedAttempts: 5, // Lock after 5 failures (default)
LockoutDuration: 15 * time.Minute, // 15-minute lockout (default)
CredentialStuffingDetection: true, // Detect credential lists
BruteForceDetection: true, // Detect brute-force patterns
},

Locked-out users can be unblocked from the dashboard or via the API.

Custom WAF Rules

You can add custom WAF rules to detect application-specific attack patterns:

internal/routes/routes.go
WAF: sentinel.WAFConfig{
Enabled: true,
Mode: sentinel.ModeBlock,
CustomRules: []sentinel.WAFRule{
{
ID: "block-admin-enum",
Name: "Block admin enumeration",
Pattern: `(?i)/(wp-admin|phpmyadmin|administrator)`,
AppliesTo: []string{"path"},
Severity: sentinel.SeverityMedium,
Action: "block",
Enabled: true,
},
},
ExcludeRoutes: []string{"/api/health"}, // Skip WAF for health checks
},

Custom rules can also be managed at runtime from the dashboard without redeploying.

AI-Powered Analysis

If you have an AI API key configured (Claude, OpenAI, or Gemini), Sentinel can use it for intelligent threat analysis:

internal/routes/routes.go
AI: &sentinel.AIConfig{
Provider: sentinel.Claude, // or sentinel.OpenAI, sentinel.Gemini
APIKey: cfg.AIAPIKey, // Reuse your existing AI API key
DailySummary: true, // Generate daily threat summaries
},
  • Threat analysis -- AI evaluates individual threats and provides context
  • Actor assessment -- AI profiles threat actors and predicts intent
  • Daily summaries -- automated security briefings
  • Natural language queries -- ask questions about your security data
  • WAF recommendations -- AI suggests new rules based on attack patterns

Alerts

Sentinel can send real-time alerts when threats are detected. Configure one or more channels:

internal/routes/routes.go
Alerts: sentinel.AlertConfig{
MinSeverity: sentinel.SeverityHigh,
Slack: &sentinel.SlackConfig{
WebhookURL: "https://hooks.slack.com/services/...",
},
Email: &sentinel.EmailConfig{
SMTPHost: "smtp.example.com",
SMTPPort: 587,
Username: "alerts@example.com",
Password: "smtp-password",
Recipients: []string{"security@example.com"},
},
Webhook: &sentinel.WebhookConfig{
URL: "https://your-siem.example.com/webhook",
Headers: map[string]string{"X-Token": "your-token"},
},
},

Production Checklist

Before deploying to production, make sure to:

1Change SENTINEL_PASSWORD and SENTINEL_SECRET_KEY to strong, unique values
2Switch WAF mode from ModeLog to ModeBlock after reviewing logs for false positives
3Configure at least one alert channel (Slack, email, or webhook)
4Review rate limits and adjust for your expected traffic
5Set up IP reputation checking with an AbuseIPDB API key for auto-blocking known bad actors
6Consider enabling AI-powered analysis for automated threat intelligence

Disabling Sentinel

If you don't need Sentinel, set SENTINEL_ENABLED=false in your .env file. The app will run normally without any security middleware or dashboard -- no code changes needed.