Security Considerations
The core-developer package provides powerful administrative capabilities that require careful security controls. This document outlines the security model, known risks, and mitigation strategies.
Threat Model
Assets Protected
- Application logs - May contain tokens, passwords, PII in error messages
- Database access - Read-only query execution against production data
- SSH keys - Encrypted private keys for server connections
- Cache data - Application cache, session data, config cache
- Route information - Full application route structure
Threat Actors
- Unauthorized users - Non-Hades users attempting to access dev tools
- Compromised Hades account - Attacker with valid Hades credentials
- SSRF/Injection - Attacker manipulating dev tools to access internal resources
- Data exfiltration - Extracting sensitive data via dev tools
Authorization Model
Hades Tier Requirement
All developer tools require "Hades" access, verified via the isHades() method on the User model. This is enforced at multiple layers:
| Layer | Implementation | File |
|---|---|---|
| Middleware | RequireHades::handle() | src/Middleware/RequireHades.php |
| Component | checkHadesAccess() in mount() | All Livewire components |
| API | Controller authorize() calls | src/Controllers/DevController.php |
| Menu | admin flag filtering | src/Boot.php |
Defence in Depth
The authorization is intentionally redundant:
- API routes use
RequireHadesmiddleware - Livewire components check in
mount() - Some controller methods call
$this->authorize()
This ensures access is blocked even if one layer fails.
Known Issue: Test Environment
Tests currently pass without setting Hades tier on the test user. This suggests authorization may not be properly enforced in the test environment. See TODO.md for remediation.
Data Protection
Log Redaction
The LogReaderService automatically redacts sensitive patterns before displaying logs:
| Pattern | Replacement |
|---|---|
| Stripe API keys | [STRIPE_KEY_REDACTED] |
| GitHub tokens | [GITHUB_TOKEN_REDACTED] |
| Bearer tokens | Bearer [TOKEN_REDACTED] |
| API keys/secrets | [KEY_REDACTED] / [REDACTED] |
| AWS credentials | [AWS_KEY_REDACTED] / [AWS_SECRET_REDACTED] |
| Database URLs | Connection strings with [USER]:[PASS] |
| Email addresses | Partial: jo***@example.com |
| IP addresses | Partial: 192.168.xxx.xxx |
| Credit card numbers | [CARD_REDACTED] |
| JWT tokens | [JWT_REDACTED] |
| Private keys | [PRIVATE_KEY_REDACTED] |
Limitation: Patterns are regex-based and may not catch all sensitive data. Custom application secrets with non-standard formats will not be redacted.
SSH Key Storage
Server private keys are:
- Encrypted at rest using Laravel's
encryptedcast - Hidden from serialization (
$hiddenarray) - Never exposed in API responses or views
- Stored in
textcolumn (supports long keys)
Database Query Tool
The database query component restricts access to read-only operations:
protected const ALLOWED_STATEMENTS = ['SELECT', 'SHOW', 'DESCRIBE', 'EXPLAIN'];Known Risk: The current implementation only checks the first word, which does not prevent:
- Stacked queries:
SELECT 1; DROP TABLE users - Subqueries with side effects (MySQL stored procedures)
Mitigation: Use a proper SQL parser or prevent semicolons entirely.
Session Data Exposure
The /hub/api/dev/session endpoint exposes:
- Session ID
- User IP address
- User agent (truncated to 100 chars)
- Request method and URL
This is intentional for debugging but could be abused for session hijacking if credentials are compromised.
Rate Limiting
All API endpoints have rate limits to prevent abuse:
| Endpoint | Limit | Rationale |
|---|---|---|
| Cache clear | 10/min | Prevent DoS via rapid cache invalidation |
| Log reading | 30/min | Limit log scraping |
| Route listing | 30/min | Prevent enumeration attacks |
| Session info | 60/min | Higher limit for debugging workflows |
Rate limits are per-user (authenticated) or per-IP (unauthenticated).
SSH Connection Security
Key Handling
The testConnection() method in Servers.php creates a temporary key file:
$tempKeyPath = sys_get_temp_dir().'/ssh_test_'.uniqid();
file_put_contents($tempKeyPath, $server->getDecryptedPrivateKey());
chmod($tempKeyPath, 0600);Risk: Predictable filename pattern and race condition window between write and use.
Recommendation: Use tempnam() for unique filename, write with restrictive umask.
Connection Validation
StrictHostKeyChecking=nois used for convenience but prevents MITM detectionBatchMode=yesprevents interactive promptsConnectTimeout=10limits hanging connections
Workspace Isolation
The RemoteServerManager::connect() method validates workspace ownership before connecting:
if (! $server->belongsToCurrentWorkspace()) {
throw new SshConnectionException('Unauthorised access to server.', $server->name);
}This prevents cross-tenant server access.
Route Testing Security
Environment Restriction
Route testing is only available in local and testing environments:
public function isTestingAllowed(): bool
{
return App::environment(['local', 'testing']);
}This prevents accidental data modification in production.
Destructive Operation Warnings
Routes using DELETE, PUT, PATCH, POST methods are marked as destructive and show warnings in the UI.
CSRF Consideration
Test requests bypass CSRF as they are internal requests. The X-Requested-With: XMLHttpRequest header is set by default.
Cookie Security
Hades Cookie
The SetHadesCookie listener sets a cookie on login:
| Attribute | Value | Purpose |
|---|---|---|
| Value | Encrypted token | Validates Hades status |
| Duration | 1 year | Long-lived for convenience |
| HttpOnly | true | Prevents XSS access |
| Secure | true (production) | HTTPS only in production |
| SameSite | lax | CSRF protection |
Icon Settings Cookie
ApplyIconSettings middleware reads icon-style and icon-size cookies set by JavaScript. These are stored in session for Blade component access.
Risk: Cookie values are user-controlled. Ensure they are properly escaped in views.
Audit Logging
Logged Actions
| Action | What's Logged |
|---|---|
| Log clear | user_id, email, previous_size_bytes, IP |
| Database query | user_id, email, query, row_count, execution_time, IP |
| Blocked query | user_id, email, query (attempted), IP |
| Route test | user_id, route, method, IP |
| Server failure | Server ID, failure reason (via activity log) |
Activity Log
Server model uses Spatie ActivityLog for tracking changes:
- Logged fields: name, ip, port, user, status
- Only dirty attributes logged
- Empty logs suppressed
Third-Party Security
Telescope
- Sensitive headers hidden:
cookie,x-csrf-token,x-xsrf-token - Sensitive parameters hidden:
_token - Gate restricts to Hades users (production) or all users (local)
Horizon
- Gate restricts to Hades users
- Notifications configured via config (not hardcoded emails)
Security Checklist for New Features
When adding new developer tools:
- [ ] Enforce Hades authorization in middleware AND component
- [ ] Add rate limiting for API endpoints
- [ ] Redact sensitive data in output
- [ ] Audit destructive operations
- [ ] Restrict environment (local/testing) for dangerous features
- [ ] Validate and sanitize all user input
- [ ] Use prepared statements for database queries
- [ ] Clean up temporary files/resources
- [ ] Document security considerations
Incident Response
If Hades credentials are compromised:
- Revoke the user's Hades access
- Rotate
HADES_TOKENenvironment variable - Review audit logs for suspicious activity
- Check server access logs for SSH activity
- Consider rotating SSH keys for connected servers
If SSH key is exposed:
- Delete the server record immediately
- Regenerate SSH key on the actual server
- Review server logs for unauthorized access
- Update the server record with new key
Recommendations for Production
- Separate Hades token per environment - Don't use same token across staging/production
- Regular audit log review - Monitor for unusual access patterns
- Limit Hades users - Only grant to essential personnel
- Use hardware keys - For servers, prefer hardware security modules
- Network segmentation - Restrict admin panel to internal networks
- Two-factor authentication - Require 2FA for Hades-tier accounts
- Session timeout - Consider shorter session duration for Hades users