← Back to Development Workflow
Security Best Practices
Last Updated: November 4, 2025
Status: Active
Overview
This document consolidates security best practices, audit findings, and configuration guidelines for the KMP application. It covers both development and production security requirements.
Table of Contents
- Security Posture
- Cookie Configuration
- CSRF Protection
- Security Headers
- Session Security
- Development vs. Production
- Penetration Testing Results
- Security Checklist
Security Posture
Current Status: EXCELLENT - All identified vulnerabilities resolved
Based on penetration testing conducted November 3, 2025:
- Critical Vulnerabilities: 0
- High Risk Vulnerabilities: 0 (1 false positive identified and cleared)
- Medium Risk Vulnerabilities: 0 (all fixed)
- Low Risk Issues: 0 (all fixed)
- False Positives: 1 (Mass Assignment - properly mitigated)
Cookie Configuration
Development Mode (debug=true)
Purpose: Support local development with HTTP, localhost, and IP address access.
Settings:
session.cookie_secure=false- Allows HTTPsession.cookie_samesite=Lax- Safari compatiblesession.cookie_domain=''- Works with localhost and IP addresses- CSRF
secure=false- Functions over HTTP - CSRF
sameSite=Lax- Cross-origin compatible
Use Cases:
- ✅ Access via localhost (http://localhost:8080)
- ✅ Access via IP address (http://192.168.0.253:8080)
- ✅ Works in Safari (strict cookie enforcement)
- ✅ No HTTPS required for development
- ✅ Test on local network devices
Production Mode (debug=false)
Purpose: Maximum security for production deployment.
Settings:
session.cookie_secure=true- HTTPS onlysession.cookie_samesite=Strict- Maximum CSRF protectionsession.cookie_httponly=true- Prevent JavaScript accesssession.use_strict_mode=true- Validate session IDs- CSRF
secure=true- HTTPS only - CSRF
sameSite=Strict- Maximum protection - HSTS header enforced - 24-hour max-age
Security Guarantees:
- ✅ Session cookies only sent over HTTPS
- ✅ CSRF cookies only sent over HTTPS
- ✅ Strict SameSite policy prevents cross-site requests
- ✅ HTTP-only cookies prevent XSS attacks
- ✅ Strict session ID validation
- ✅ HSTS enforces HTTPS for 24 hours
Configuration Files
1. Application.php - CSRF Protection
Location: app/src/Application.php (Lines 406-414)
new CsrfProtectionMiddleware([
'httponly' => true, // Always prevent JavaScript access
'secure' => !Configure::read('debug'), // false in dev, true in prod
'sameSite' => Configure::read('debug') ? 'Lax' : 'Strict',
])
2. app.php - Session Configuration
Location: app/config/app.php
'Session' => [
'defaults' => 'php',
'timeout' => 30,
'cookie' => 'PHPSESSID',
'ini' => [
'session.cookie_secure' => true,
'session.cookie_httponly' => true,
'session.cookie_samesite' => 'Strict',
'session.use_strict_mode' => true,
],
],
Session cookie security attributes (cookie_secure, cookie_samesite) can be overridden in app_local.php per environment. The development container’s app_local.php does not currently override session settings; cookie behavior is toggled via bootstrap.php security validation warnings.
3. bootstrap.php - Security Validation
Location: app/config/bootstrap.php (Lines 100-144)
Runtime security checks warn if production is running with insecure settings.
CSRF Protection
Middleware: CsrfProtectionMiddleware
Features:
- Token validation on all POST/PUT/PATCH/DELETE requests
- HTTP-only cookies prevent JavaScript token theft
- Conditional secure flag based on environment
- SameSite protection against cross-site attacks
Implementation:
// In Application.php middleware stack
->add(new CsrfProtectionMiddleware([
'httponly' => true,
'secure' => !Configure::read('debug'),
'sameSite' => Configure::read('debug') ? 'Lax' : 'Strict',
]))
Token Usage in Forms:
<?= $this->Form->create($entity) ?>
<!-- CSRF token automatically included -->
<?= $this->Form->end() ?>
Security Headers
Content Security Policy (CSP):
Location: app/src/Application.php (Lines 340-390)
$csp = "default-src 'self'; "
. "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; "
. "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; "
. "font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net data:; "
. "img-src 'self' data: https://*.tile.openstreetmap.org https://*.openstreetmap.org; "
. "connect-src 'self' https://*.tile.openstreetmap.org; "
. "frame-ancestors 'none'; "
. "base-uri 'self'; "
. "form-action 'self';";
// Production only: upgrade insecure requests
if (!$isDevelopment) {
$csp .= "; upgrade-insecure-requests";
}
$response = $response->withHeader('Content-Security-Policy', $csp);
HTTP Strict Transport Security (HSTS):
// Production only
if (!$isDevelopment) {
$response = $response->withHeader(
'Strict-Transport-Security',
'max-age=86400; includeSubDomains'
);
}
Other Security Headers:
X-Frame-Options: DENY- Prevent clickjackingX-Content-Type-Options: nosniff- Prevent MIME sniffingReferrer-Policy: strict-origin-when-cross-origin- Control referrer information
Session Security
Session Configuration:
'Session' => [
'defaults' => 'php',
'timeout' => 30, // 30 minutes
'cookie' => 'PHPSESSID',
'ini' => [
'session.cookie_secure' => true, // HTTPS only (in production)
'session.cookie_httponly' => true, // Prevent JavaScript access
'session.cookie_samesite' => 'Strict', // CSRF protection (in production)
'session.use_strict_mode' => true, // Validate session IDs
],
],
Session Timeout:
- Client-side: 30 minutes (cookie timeout)
- Server-side: 30 minutes (garbage collection)
- Idle timeout: Handled by cookie expiration
Session Regeneration:
- Automatic regeneration on login
- Prevents session fixation attacks
- Handled by CakePHP authentication plugin
Development vs. Production
Environment Configuration
Development (.env):
DEBUG=true
Production (.env):
DEBUG=false
Security Differences
| Feature | Development | Production |
|---|---|---|
| Session Cookie Secure | false (HTTP allowed) |
true (HTTPS only) |
| Session SameSite | Lax (Safari compatible) |
Strict (maximum protection) |
| CSRF Cookie Secure | false |
true |
| CSRF SameSite | Lax |
Strict |
| HSTS Header | Not sent | Enforced (24 hours) |
| CSP upgrade-insecure-requests | Not included | Included |
| Service Workers | Gracefully degrade | Full support with HTTPS |
Development Benefits
✅ Browser Compatibility:
- Works in Safari with strict cookie enforcement
- Works in all modern browsers
- No certificate warnings or errors
✅ Network Flexibility:
- Access via localhost (http://localhost:8080)
- Access via IP address (http://192.168.0.253:8080)
- Access via 127.0.0.1
- Test on mobile devices via local network
✅ No HTTPS Required:
- Develop without SSL certificates
- No mixed content warnings
- Faster iteration cycle
Production Guarantees
✅ CSRF Protection:
- CSRF cookies only sent over HTTPS
- Strict SameSite policy
- HTTP-only cookies prevent JavaScript access
✅ Session Security:
- Session cookies only sent over HTTPS
- Strict SameSite policy
- Strict session ID validation
✅ Transport Security:
- HSTS header enforces HTTPS
- CSP automatically upgrades HTTP to HTTPS
- All security headers active
✅ Validation:
- Runtime checks warn if misconfigured
- Logs document security mode
- Prevents accidental insecure deployment
Penetration Testing Results
Test Overview
Date: November 3, 2025
Scope: HTTP surface security testing
Test Accounts: Various privilege levels (basic user through super user)
Result: All vulnerabilities resolved or verified as false positives
Findings Summary
VULN-001: Mass Assignment (FALSE POSITIVE)
Status: ✅ NOT A VULNERABILITY
Initial Concern: Member entity’s $_accessible array appeared to allow modification of sensitive fields.
Actual Finding: Application properly segregates user-level and admin-level edits:
- Separate Controller Actions:
partialEdit()- Users editing themselves (manual field assignment)edit()- Administrators with elevated permissions (uses patchEntity)
- Authorization Enforcement:
- Regular users can only
partialEditthemselves - Policy check:
MemberPolicy::canPartialEdit()validates user owns record - Admin edit requires
canEditpermission
- Regular users can only
- Manual Field Assignment in partialEdit():
public function partialEdit($id = null) { $member = $this->Members->get($id); $this->Authorization->authorize($member); if ($this->request->is(['patch', 'post', 'put'])) { // SECURE: Manually sets ONLY allowed fields $member->title = $this->request->getData('title'); $member->sca_name = $this->request->getData('sca_name'); // ... only safe fields assigned // Sensitive fields (status, membership_expires_on) are NOT assigned // even if attacker submits them } }
Defense in Depth:
- ✅ Separate actions for different privilege levels
- ✅ Manual field assignment (no mass assignment risk)
- ✅ Authorization policy enforcement
- ✅ Route-level access control
VULN-002: Duplicate HTML IDs (FIXED)
Status: ✅ FIXED
Severity: Medium (was accessibility issue, not security)
Issue: Multiple modal elements using same IDs caused accessibility problems.
Fix: Updated modal IDs to be unique per context.
VULN-003: Autocomplete Attributes (FIXED)
Status: ✅ FIXED
Severity: Low (password management UX)
Issue: Missing autocomplete attributes on password fields.
Fix: Added proper autocomplete attributes:
- Login:
autocomplete="current-password" - Registration:
autocomplete="new-password" - Password change: Appropriate attributes per field
Security Testing Best Practices
Regular Testing:
- Run penetration tests before major releases
- Test with multiple privilege levels
- Verify authorization at every endpoint
- Test both authenticated and public access
Automated Security Checks:
# Dependency vulnerability scanning
composer audit
# PHP security checker
./security-checker.sh
Security Checklist
Pre-Deployment
- Set
DEBUG=falsein production .env - Verify HTTPS is configured on web server
- Check application logs for security warnings
- Test that cookies are marked
Securein browser dev tools - Verify HSTS header is present in responses
- Confirm login works over HTTPS only
- Run
composer auditfor dependency vulnerabilities - Review and update CSP headers as needed
Development Setup
- Set
DEBUG=truein .env - Verify cookies work over HTTP
- Test in Safari for compatibility
- Test on mobile devices via IP address
- Check browser console for CSP violations
Code Review Security Checks
Controller Actions:
- All actions have authorization checks
- Manual field assignment for user-editable forms
- patchEntity only used with proper $_accessible configuration
- CSRF protection enabled for POST/PUT/PATCH/DELETE
- Input validation on all user-provided data
Templates:
- Output properly escaped (automatic via CakePHP helpers)
- No direct
echoof user input without escaping - Forms use
$this->Form->create()for CSRF tokens - Links use
$this->Html->link()for proper escaping
Policies:
- Authorization checks at both table and entity level
- Branch scoping enforced where appropriate
- Temporal validation for time-sensitive permissions
- Proper fallback to deny access if unsure
Database:
- Parameterized queries (ORM handles this)
- No raw SQL with user input
- Proper foreign key constraints
- Soft deletes instead of hard deletes for audit trail
Incident Response
If Security Issue Discovered:
- Assess Severity:
- Critical: Immediate fix required
- High: Fix within 24 hours
- Medium: Fix in next release
- Low: Fix as time permits
- Document:
- What the vulnerability is
- How it was discovered
- What data/systems are affected
- What actions have been taken
- Fix and Test:
- Implement fix
- Add test case to prevent regression
- Verify fix doesn’t introduce new issues
- Document fix in code comments
- Deploy:
- Emergency deployment for critical issues
- Include in next scheduled release for lower severity
- Update security documentation
- Review:
- Conduct post-mortem
- Update security practices
- Add to testing checklist
Public ID System
Overview
The KMP application implements a Public ID system to replace the exposure of internal database IDs to client-side code. This is a critical security and privacy enhancement that prevents information leakage and enumeration attacks.
The Problem: Exposing Internal IDs
Exposing sequential database IDs to clients creates several security problems:
- Information Leakage - Sequential IDs reveal record counts and creation order
- Enumeration Attacks - Attackers can iterate through all records systematically
- Privacy Violations - Deletions and gaps become visible
- Predictability - Easy to guess related record IDs
Example Vulnerability:
// Attacker can iterate through all records
for (let id = 1; id < 10000; id++) {
fetch(`/members/view/${id}`)
}
The Solution: Public IDs
Public IDs are non-sequential, unpredictable identifiers safe to expose to clients:
Internal ID: 123 (sequential, predictable)
Public ID: a7fK9mP2 (random, unpredictable)
Characteristics:
- Format: 8-character alphanumeric (Base62: a-z, A-Z, 2-9)
- Uniqueness: 62^8 = 218 trillion possible combinations
- Performance: Indexed for O(1) lookups (same as primary keys)
- Human-Readable: Excludes confusing characters (0/O, 1/l/I)
Implementation
PublicIdBehavior provides public ID functionality to any table:
// Add to any Table class
class MembersTable extends Table
{
public function initialize(array $config): void
{
parent::initialize($config);
$this->addBehavior('PublicId');
}
}
Usage in Controllers:
// Before: Exposes internal ID
public function view($id = null)
{
$member = $this->Members->get($id);
}
// After: Uses public ID
public function view($publicId = null)
{
$member = $this->Members->getByPublicId($publicId);
}
Usage in Templates:
// Before
<?= $this->Html->link('View', ['action' => 'view', $member->id]) ?>
// After
<?= $this->Html->link('View', ['action' => 'view', $member->public_id]) ?>
Security Benefits
Before (Vulnerable):
❌ Sequential IDs exposed
❌ Information leakage (count, order, deletions)
❌ Enumeration attacks possible
❌ Predictable identifiers
After (Secure):
✅ Random, non-sequential IDs
✅ No information leakage
✅ Enumeration attacks prevented
✅ Unpredictable identifiers
✅ Same performance (indexed lookups)
Attack Prevention Examples:
- Record Enumeration - Attackers cannot systematically discover records
- Information Gathering - No way to determine total record count or creation order
- Related Record Discovery - Cannot guess related record IDs
Performance
- Lookup Speed: O(1) with unique index (same as primary key)
- Storage Overhead: 8 bytes per record (negligible)
- Index Overhead: Similar to INT index, very fast lookups
Generating Public IDs
For existing records, use the console command:
# Generate for all tables
bin/cake generate_public_ids --all
# Generate for specific table
bin/cake generate_public_ids members
# Dry run to preview
bin/cake generate_public_ids --all --dry-run
Database Schema
-- Public ID column structure
ALTER TABLE members ADD COLUMN public_id VARCHAR(8) UNIQUE;
CREATE UNIQUE INDEX idx_members_public_id ON members(public_id);
-- Internal relations still use id (foreign keys)
-- Public IDs are only for client-facing references
Migration Strategy
- Add Columns - Run migrations (zero downtime)
- Generate IDs - Populate existing records
- Update Code - Add behavior to tables
- Update Controllers - Use public_id instead of id
- Update Templates - Use public_id in links
- Update JavaScript - Use public_id in AJAX calls
Testing Public IDs
Unit Tests:
public function testPublicIdGeneration()
{
$member = $this->Members->newEntity(['sca_name' => 'Test']);
$this->Members->save($member);
$this->assertNotNull($member->public_id);
$this->assertEquals(8, strlen($member->public_id));
$this->assertMatchesRegularExpression('/^[a-zA-Z0-9]{8}$/', $member->public_id);
}
Integration Tests:
public function testViewWithPublicId()
{
$member = $this->createMember();
$this->get('/members/view/' . $member->public_id);
$this->assertResponseOk();
}
Files
Created:
app/src/Model/Behavior/PublicIdBehavior.php- Core behaviorapp/src/Command/GeneratePublicIdsCommand.php- CLI commandapp/config/Migrations/*_AddPublicId*.php- Database migrations
Plugin Integration:
- See Extending KMP for adding public IDs to plugin tables
Testing Security
Manual Security Testing
Authentication:
# Test login
curl -c cookies.txt -d "username=test@example.com&password=wrong" \
https://example.com/members/login
# Verify session cookie has Secure flag
cat cookies.txt | grep "Secure"
# Test protected endpoint without auth (should fail)
curl -b cookies.txt https://example.com/members/index
Authorization:
- Test each endpoint with different user privilege levels
- Verify branch scoping limits data access
- Test policy checks prevent unauthorized actions
- Verify temporal validation rejects expired warrants
CSRF Protection:
# Test POST without CSRF token (should fail)
curl -X POST -b cookies.txt https://example.com/members/add
# Test with invalid CSRF token (should fail)
curl -X POST -b cookies.txt -d "_csrfToken=invalid&..." \
https://example.com/members/add
Automated Security Scanning
Composer Audit:
cd app
composer audit
Security Checker:
./security-checker.sh
CodeQL (if configured):
# Run CodeQL analysis
codeql database analyze
Session Security Configuration
Session management is critical for protecting user authentication and preventing session hijacking attacks. KMP implements security best practices through configuration.
Session Configuration Overview
KMP’s session configuration in config/app.php:
"Session" => [
"defaults" => "php", // Use PHP's default session handling
"timeout" => 30, // 30-minute session timeout
"cookie" => "PHPSESSID",
"ini" => [
// Secure cookies require HTTPS
"session.cookie_secure" => true,
// Prevent JavaScript access (XSS protection)
"session.cookie_httponly" => true,
// CSRF protection via SameSite policy
"session.cookie_samesite" => "Strict",
// Validate session IDs for security
"session.use_strict_mode" => true,
],
],
Session Security Features
| Feature | Purpose | Setting |
|---|---|---|
| Secure Cookies | Require HTTPS | session.cookie_secure=true |
| HttpOnly Flag | Prevent XSS access | session.cookie_httponly=true |
| SameSite Policy | Prevent CSRF | session.cookie_samesite=Strict |
| Strict Mode | Validate IDs | session.use_strict_mode=true |
| Session Timeout | Auto-logout | 30 minutes |
Cookie Security Attributes
Secure Attribute:
Set-Cookie: PHPSESSID=abc123; Secure; HttpOnly; SameSite=Strict; Path=/
- ✅
Secure: Only sent over HTTPS - ✅
HttpOnly: Cannot be accessed by JavaScript - ✅
SameSite=Strict: Only sent with same-site requests - ✅
Path=/: Available application-wide
Session Timeout Behavior
30-Minute Timeout:
User Login
↓
Session created with TTL = 30 minutes
↓
Active use extends timeout
↓
30 minutes of inactivity
↓
Session expires
↓
User redirected to login
Configuration:
To change timeout duration, modify in config/app.php:
"Session" => [
"timeout" => 60, // 60-minute timeout
],
Session Storage Options
KMP defaults to PHP file-based sessions. Alternative options available:
1. PHP File Sessions (Default)
"Session" => [
"defaults" => "php", // PHP's native file-based sessions
],
Advantages:
- No additional dependencies
- Simple configuration
- Works on single servers
Disadvantages:
- Not shared between servers
- Cleared on PHP restart
- File system performance limits
2. Database Sessions
Enable database-backed sessions:
"Session" => [
"defaults" => "database",
"handler" => [
"engine" => DatabaseSession::class,
"table" => "sessions",
"connection" => "default",
],
],
Advantages:
- Shared across servers
- Survives PHP restarts
- Easy to query/audit
Disadvantages:
- Database overhead
- Requires sessions table
- Slower than file sessions
3. Cache Sessions
Use cache backend for sessions:
"Session" => [
"defaults" => "cache",
"handler" => [
"engine" => CacheSession::class,
"config" => "default",
],
],
Advantages:
- Fast in-memory storage
- Survives restarts (if using persistent cache)
- Good for high-traffic
Disadvantages:
- Limited by cache size
- Lost if cache cleared
Development vs. Production Settings
Development Mode (DEBUG=true):
PHP ini settings adjusted for development:
// config/app.php (debug=true)
"Session" => [
"ini" => [
"session.cookie_secure" => false, // Allow HTTP
"session.cookie_httponly" => true,
"session.cookie_samesite" => "Lax", // Works with CORS
"session.use_strict_mode" => true,
],
],
- ✅ HTTP allowed for localhost
- ✅ Works with IP addresses
- ✅ Easier cross-origin testing
Production Mode (DEBUG=false):
// config/app.php (debug=false)
"Session" => [
"ini" => [
"session.cookie_secure" => true, // HTTPS only
"session.cookie_httponly" => true,
"session.cookie_samesite" => "Strict", // No CORS
"session.use_strict_mode" => true,
],
],
- ✅ HTTPS enforced
- ✅ Maximum security
- ✅ No cross-site cookies
Session Best Practices
- Regenerate After Login
// In authentication handler session_regenerate_id(true); // Invalidates old session ID - Destroy on Logout
session_destroy(); // Completely clear session - Monitor for Hijacking
// Store user agent in session to detect changes if ($_SERVER['HTTP_USER_AGENT'] !== $_SESSION['user_agent']) { session_destroy(); redirect('/login'); // Potential hijack } - Clear Sensitive Data
// Don't store passwords or API keys in session unset($_SESSION['password']); - Use HTTPS
- Required for Secure cookies
- Protects session cookies in transit
Encryption and Cryptographic Salt
Cryptographic operations require secure, random salt values for password hashing, token generation, and encryption.
Security Salt Configuration
The security salt is the foundation of password and token security:
"Security" => [
"salt" => env("SECURITY_SALT"),
],
Generating a Secure Salt
Use a cryptographic random generator:
# Generate a 64-character random salt
php -r "echo bin2hex(random_bytes(32)) . PHP_EOL;"
Output Example:
DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgAC7ChtP7k4aYDLG0xVt7z8Fkj4UzP
Salt Requirements
| Requirement | Detail |
|---|---|
| Length | Minimum 32 characters (64+ recommended) |
| Randomness | Cryptographically random (use generator) |
| Uniqueness | Different for each environment |
| Secrecy | Never committed to version control |
| Storage | In .env file, not in code |
Salt Uses
The security salt is used for:
- Password Hashing
$hashedPassword = password_hash($password, PASSWORD_BCRYPT); - CSRF Token Generation
$csrfToken = Security::hash(session_id() . $salt); - Encryption Keys
$encryptionKey = hash('sha256', $salt . 'encryption'); - Cookie Signing
Security::hash($cookieData . $salt);
Rotating the Salt
When to Rotate:
- Suspected compromise
- Major version upgrades
- Scheduled rotation (yearly recommended)
- After security incident
Rotation Process:
- Generate new salt:
php -r "echo bin2hex(random_bytes(32)) . PHP_EOL;" - Update .env:
# Update SECURITY_SALT=new_value - Force re-authentication:
// Invalidate all existing sessions bin/cake sessions delete_all - Reset user passwords:
- Send password reset emails
- Users must set new passwords
- Monitor logs:
tail -f app/logs/error.log
Password Hashing
Password hashing uses bcrypt with the security salt:
// Hashing a password
$hashedPassword = password_hash($password, PASSWORD_BCRYPT, [
'cost' => 12, // Computational cost (higher = slower/more secure)
'salt' => $securitySalt,
]);
// Verifying a password
if (password_verify($plainPassword, $hashedPassword)) {
// Password matches
}
Cost Factor:
- Cost 10-11: Fast (0.1 seconds)
- Cost 12: Balanced (0.25 seconds)
- Cost 13+: Slow (1+ second) - GPU resistant
For production, use cost 12 or higher.
CSRF Token Security
CSRF tokens prevent cross-site request forgery attacks:
"Security" => [
"salt" => env("SECURITY_SALT"),
],
// In forms
<?= $this->Form->create() ?>
<?= $this->Form->control('...') ?>
<!-- Automatically includes hidden CSRF token -->
<?= $this->Form->end() ?>
CSRF Token Attributes:
| Attribute | Value |
|---|---|
| Name | _csrfToken |
| Expiration | Session lifetime |
| Validation | Server-side in middleware |
| Storage | Session + Hidden form field |
Secure Cookie Signing
Cookies can be signed with the security salt to prevent tampering:
// Sign a cookie
$signedValue = Security::hash($unsafeValue . $salt, 'sha256');
// Verify signature
$expectedHash = Security::hash($value . $salt, 'sha256');
if ($signedValue !== $expectedHash) {
// Cookie was tampered with
}
Environment-Specific Salts
Important: Each environment must have unique salts.
Development (.env):
SECURITY_SALT=dev_salt_not_for_production_change_me
Production (.env):
SECURITY_SALT=cryptographically_random_production_salt_64_chars_here
Compromised development salt doesn’t affect production.
Related Documentation
- RBAC Security Architecture - Detailed authorization system
- Development Workflow - Development best practices
- Deployment - Production deployment procedures
- Environment Variables - Sensitive configuration
Quick Reference
Development Mode:
# .env
DEBUG=true
# Allows HTTP, works with Safari, IP addresses
Production Mode:
# .env
DEBUG=false
# Requires HTTPS, maximum security
Security Audit:
- Status: EXCELLENT
- Last Test: November 3, 2025
- Critical Issues: 0
- All vulnerabilities resolved
Key Security Features:
- ✅ CSRF protection with secure cookies
- ✅ Session security with strict validation
- ✅ CSP headers with proper directives
- ✅ HSTS enforcement in production
- ✅ Defense in depth authorization
- ✅ Temporal warrant validation