Home Doh Ref
Dohballs
  • 📁 doh_chat
  • 📁 doh_modules
    • 📦 dataforge
    • 📦 express
    • 📁 sso
    • 📁 user

Security Audit

A comprehensive security scanning and auditing system for Doh applications. Evaluates application security posture across authentication, server configuration, database, input validation, and permissions — with a web dashboard, CLI tool, and persistent audit logging.

Features

  • 25 Security Checks across 6 categories with weighted scoring and letter grades (A–F)
  • Web Dashboard at /admin/security with score visualization, category breakdowns, and expandable check details
  • CLI Tool via doh audit for terminal and CI/CD integration
  • Audit Logging with persistent event storage and statistics
  • Autofix Support for checks that provide automated remediation
  • Permission-Based Access with separate read and write permissions

Installation

Add to your boot.pod.yaml:

host_load:
  - security_audit

Usage

Web Dashboard

Navigate to /admin/security to access the dashboard. Users must be authenticated and have the access:security_audit permission.

CLI

doh audit                        # Run all checks
doh audit run                    # Explicit run
doh audit --category auth        # Run only auth checks
doh audit --json                 # JSON output for CI/CD
doh audit --fix                  # Run checks then apply autofixes
doh audit log                    # Show recent audit log
doh audit log --limit 100        # Show 100 recent entries
doh audit --help                 # Show help

The CLI exits with code 1 if any checks fail, making it suitable for CI/CD pipelines.

Granting Access

Assign the security_audit permission group to users who should access the audit system:

await Doh.assignPermissionGroup(user, 'security_audit');

This grants both access:security_audit (view results and logs) and manage:security_audit (apply autofixes).

Security Checks

Authentication & Tokens (10 checks)

Check Severity Description
auth.jwt_secret_strength Critical JWT secret length (64+ chars) and entropy (3.5+)
auth.jwt_secrets_differ Critical JWT and refresh secrets are different values
auth.token_expiration Medium Access token ≤7d, refresh token ≤90d
auth.secure_cookie_flags High Cookies set secure, httpOnly, sameSite
auth.password_policy Medium Min length ≥8, requires letter + number + special
auth.bcrypt_rounds Medium Bcrypt rounds ≥10
auth.login_rate_limit High Max login attempts ≤10, lockout ≥60s
auth.password_reset_rate_limit High Password reset routes have rate limiting
auth.oauth_xss_intermediate Critical No unescaped template literals in OAuth redirect scripts
auth.oauth_token_storage High Tokens not written to localStorage via inline script

Server Configuration (7 checks)

Check Severity Description
server.helmet_enabled High Helmet middleware enabled
server.csp_configured High Content Security Policy not disabled
server.cors_not_wildcard High CORS hosts configured, no wildcard *
server.forbidden_paths High Sensitive paths (.env, .git, pod.yaml) blocked
server.body_size_limit Medium Request body limit configured and ≤50MB
server.rate_limit_enabled High Global rate limiting configured
server.debug_mode Medium Debug flags (auth_debug, debug_mode) disabled

Database Security (3 checks)

Check Severity Description
database.parameterized_queries High No SQL injection via template literals or string concat
database.db_file_permissions Medium Database files not world-readable (Unix only)
database.idea_table_id_sanitization Medium Client input sanitized before use as Idea table IDs

Input Validation (4 checks)

Check Severity Description
input.username_sanitization High Username sanitizer includes SanitizeEmail
input.password_sanitization High Password sanitizer includes SanitizePassword
input.xss_in_templates High No unescaped user data in res.send, SendContent, or inline scripts
input.eval_usage Critical No eval() or new Function() in application code

Permission System (1 check)

Check Severity Description
permissions.admin_routes_protected Critical Admin routes require requireAuth or permit()

Scoring

Each check has a severity-based weight:

Severity Weight
Critical 10
High 5
Medium 3
Low 1
Info 0

Check results map to scores: pass = full weight, warn = 50% weight, fail = 0, skip = excluded.

Grade Score
A 90–100
B 80–89
C 70–79
D 60–69
F < 60

Routes

Route Method Permission Description
/admin/security GET access:security_audit Dashboard page
/api/admin/security/run POST access:security_audit Execute audit checks
/api/admin/security/results GET access:security_audit Get cached results
/api/admin/security/fix POST manage:security_audit Apply autofix for a check
/api/admin/security/log GET access:security_audit Get paginated log entries
/api/admin/security/log/stats GET access:security_audit Get log statistics

Audit Logger

Security events are persisted to a Dataforge Idea table (security.audit_log) with 90-day retention (configurable).

Event Types

Event Source Description
audit_run Server / CLI Audit was executed
audit_fix Server Autofix was applied

Logger API (Server-Side)

// Log an event
await SecurityAuditLogger.log('audit_run', 'username', { score: 85, grade: 'B' });

// Get recent entries (newest first)
const entries = await SecurityAuditLogger.getRecent(50, 0);

// Get aggregate stats by event type
const stats = await SecurityAuditLogger.getStats();

Configuration

# boot.pod.yaml or pod.yaml
security_audit:
  enabled: true              # Enable/disable the module (default: true)
  log_retention_days: 90     # How long to keep audit log entries (default: 90)

The module also inspects these pod settings during checks:

  • express_config — helmet, CSP, CORS, rate limiting, body limit, ignored paths
  • Users — JWT secrets, token expiration, password policy, login rate limiting, sanitizers

Permissions

  • Context: security_audit
  • Permission Group: security_audit (assignable)
    • access:security_audit — View audit results and logs
    • manage:security_audit — Apply autofixes

Dependencies

  • express_router — Route handling
  • user_host — Authentication middleware
  • dataforge — Audit log persistence
Last updated: 2/9/2026