-
Notifications
You must be signed in to change notification settings - Fork 2
Security Best Practices
This page consolidates security guidance for deploying and operating TMI securely.
TMI integrates with OAuth providers for secure authentication:
- Supported Providers: GitHub, Google, Microsoft (Azure AD), SAML, and any generic OAuth 2.0 / OIDC provider
- Token Type: JWT tokens with configurable expiration and signing method (HS256, RS256, ES256)
- Flow: OAuth 2.0 authorization code flow with PKCE (S256) support
Key Settings:
- Change
TMI_JWT_SECRETfrom default in production (default is"your-secret-key") - Set appropriate JWT expiration time via
TMI_JWT_EXPIRATION_SECONDS(default: 3600 seconds / 1 hour) - Use HTTPS for all OAuth callback URLs (
TMI_OAUTH_CALLBACK_URL)
See Setting-Up-Authentication for configuration details.
TMI uses HttpOnly cookies for browser-based session management, providing XSS protection by preventing JavaScript access to tokens:
-
Access token cookie (
tmi_access_token):HttpOnly,SameSite=Lax,Path=/ -
Refresh token cookie (
tmi_refresh_token):HttpOnly,SameSite=Strict,Path=/oauth2 -
Bearer token fallback: API clients can also authenticate via
Authorization: Bearer <token>header -
Cookie configuration:
TMI_COOKIE_ENABLED(default: true),TMI_COOKIE_DOMAIN,TMI_COOKIE_SECURE(auto-derived from TLS)
TMI implements three permission levels per object:
- Owner - Full read/write/delete permissions
- Writer - Read and write permissions (cannot delete or change authorization)
- Reader - Read-only access
Authorization Rules:
- The owner field takes absolute precedence
- Highest role wins when user appears multiple times
- Use the "everyone" pseudo-group to grant access to all authenticated users
- Regular users cannot change authorization or ownership (only owner can)
For detailed rules, see the Architecture-and-Design wiki page (RBAC section).
The special "everyone" group grants access to all authenticated users:
{
"owner": "admin@example.com",
"authorization": [
{
"subject": "everyone",
"subject_type": "group",
"role": "reader"
}
]
}TMI includes automated container vulnerability scanning using Grype (Anchore):
- Scans container images for CVEs
- Reports vulnerabilities by severity level (SARIF and table formats)
- Generates SBOMs using Syft (companion tool)
Quick Start:
# Check Grype is installed
make check-grype
# Scan containers for vulnerabilities
make scan-containers
# Build containers (uses Chainguard base images)
make build-containers
# Build individual containers for faster iteration
make build-container-db # PostgreSQL only
make build-container-redis # Redis only
make build-container-tmi # TMI server only
# Generate security report
make report-containersContainer images are scanned for vulnerabilities using Grype. Scan results are reported in SARIF and table formats. Review scan output after each build to identify and remediate vulnerabilities.
TMI uses Chainguard images for enhanced container security:
-
Builder:
cgr.dev/chainguard/go:latest- Secure Go build environment -
Runtime:
cgr.dev/chainguard/static:latest- Minimal static runtime -
PostgreSQL:
cgr.dev/chainguard/postgres:latest- Secure database -
Redis:
cgr.dev/chainguard/redis:latest- Secure cache/session store
- Chainguard base images with minimal CVEs and daily updates
- Static binaries built with
CGO_ENABLED=0 - TMI server container runs as
nonroot:nonroot; Redis container runs asredis; PostgreSQL uses the Chainguard entrypoint default - No shell, package manager, or unnecessary tools in runtime (Chainguard
staticbase) - Security labels and logging enabled
- Resource limits implemented
See Container Security Guide for detailed procedures.
Enable TLS to encrypt all traffic:
TMI_SERVER_TLS_ENABLED=true
TMI_SERVER_TLS_CERT_FILE=/path/to/cert.pem
TMI_SERVER_TLS_KEY_FILE=/path/to/key.pem
TMI_SERVER_TLS_SUBJECT_NAME=your-domain.com
TMI_SERVER_HTTP_TO_HTTPS_REDIRECT=true # Redirect HTTP to HTTPSThe server enforces TLS 1.2 as the minimum version when TLS is enabled.
- Use
wss://(secure WebSocket) in production - Use
ws://(standard WebSocket) only in development - Client connections are authenticated with JWT tokens
- Run database behind firewall
- Use VPC/private networks for database access
- Restrict Redis access to application server
- Implement network policies in Kubernetes
- Connection: Use SSL/TLS for database connections
- Credentials: Store in secure vaults (not config files)
- Access Control: Use least-privilege database users
- Backups: Encrypt backups at rest
- Updates: Keep PostgreSQL patched for security updates
- Authentication: Set strong password if exposed
- Network: Keep Redis private; don't expose to internet
- Persistence: Use RDB/AOF with encryption at rest
- Memory: Monitor and limit memory usage
-
Critical: Change
TMI_JWT_SECRETfrom the default"your-secret-key"(validation rejects the default) -
Signing methods: HS256 (shared secret), RS256 (RSA keys), or ES256 (ECDSA keys) via
TMI_JWT_SIGNING_METHOD - Length: For HS256, use strong, randomly generated secrets (256+ bits)
-
Storage: Store in secure secrets vault. TMI supports AWS Secrets Manager (
TMI_SECRETS_PROVIDER=aws) and OCI Vault (TMI_SECRETS_PROVIDER=oci) natively. - Rotation: Rotate periodically and implement key versioning
- Store OAuth client secrets in secure vault
- Never commit secrets to version control
- Use environment variables, not config files
- Implement secret rotation policies
- Use certificates from trusted CAs
- Implement certificate monitoring and renewal
- Store private keys securely with restricted permissions
- Use automated certificate management (Let's Encrypt, etc.)
TMI uses structured JSON logging via Go's slog package. All log entries include request context for traceability.
- Log all authentication attempts (successes and failures)
- Log authorization changes and ownership transfers
- Log data access by role and user
- Implement centralized log collection
Log output is configured via:
-
logging.levelin config YAML (orTMI_LOG_LEVELenv var):debug,info,warn,error -
logging.log_dir: directory for log files (default:logs) -
logging.also_log_to_console: dual output to stdout and files
Since TMI uses structured JSON logging, use jq or a log aggregation tool to query security events:
# Monitor security logs in real time
tail -f logs/tmi.log | jq 'select(.msg | test("auth|login|token"))'
# Check for failed authentication attempts
cat logs/tmi.log | jq 'select(.msg | test("Failed|failed|error")) | select(.msg | test("auth|token|login"))'
# Monitor authorization changes
cat logs/tmi.log | jq 'select(.msg | test("authorization|ownership|transfer"))'Implement alerts for:
- Failed authentication attempts (repeated failures = potential attack)
- Unauthorized access attempts
- High/critical CVEs discovered
- Certificate expiration warnings
- Database connection failures
- Change
TMI_JWT_SECRETfrom default (or configure RS256/ES256 keys) - Enable TLS/HTTPS (
TMI_SERVER_TLS_ENABLED=true) - Configure OAuth providers with HTTPS callback URLs
- Set appropriate JWT expiration time (
TMI_JWT_EXPIRATION_SECONDS) - Configure CORS allowed origins (
TMI_CORS_ALLOWED_ORIGINS) - Run security scan on all container images
- Implement database access controls
- Set up backup and recovery procedures
- Configure logging and monitoring
- Review and test disaster recovery plan
TMI_BUILD_MODE=production
TMI_SERVER_TLS_ENABLED=true
TMI_SERVER_TLS_CERT_FILE=/path/to/cert.pem
TMI_SERVER_TLS_KEY_FILE=/path/to/key.pem
TMI_JWT_SECRET=<strong-random-secret>
TMI_OAUTH_CALLBACK_URL=https://your-domain.com/oauth2/callback
TMI_CORS_ALLOWED_ORIGINS=https://your-frontend-domain.com
TMI_COOKIE_SECURE=true- Use network policies to restrict traffic
- Implement pod security policies
- Use RBAC for access control
- Enable audit logging
- Scan images before deployment
- Use resource limits and quotas
If you discover a security vulnerability:
- Do not publicly disclose the vulnerability
- Report vulnerabilities by creating an issue in the repository
- Include proof of concept if possible
- Allow 90 days for patching before public disclosure
- Subscribe to security notifications
- Apply security patches promptly
- Test patches in staging before production
- Maintain an upgrade schedule (monthly recommended)
TMI-UX implements a multi-layered security approach for HTTP headers:
- Dynamic CSP: Content Security Policy is dynamically generated based on environment configuration
- Additional Headers: Configured at the deployment level (proxy/load balancer)
- Adaptive HSTS: Enabled only when TLS is available
The TMI backend API server automatically sets the following security headers on all responses via middleware:
| Header | Value | Notes |
|---|---|---|
X-Content-Type-Options |
nosniff |
Always set |
X-Frame-Options |
DENY |
Always set |
X-XSS-Protection |
0 |
Disabled per modern guidance |
Content-Security-Policy |
default-src 'self'; ... |
Dev/production variants |
Referrer-Policy |
strict-origin-when-cross-origin |
Always set |
Cache-Control |
no-store, no-cache, must-revalidate |
Prevents caching of API responses |
Permissions-Policy |
geolocation=(), microphone=(), camera=() |
Always set |
Strict-Transport-Security |
max-age=31536000; includeSubDomains |
Only when TLS is enabled |
CORS is handled via middleware with configurable allowed origins (TMI_CORS_ALLOWED_ORIGINS). In development mode (logging.is_dev=true), any origin is reflected. In production, only explicitly configured origins are allowed. Credentials are supported (Access-Control-Allow-Credentials: true).
The Angular application dynamically generates and injects a CSP meta tag that:
- Automatically includes your API URL from environment configuration
- Supports both HTTP and HTTPS API endpoints
- Provides XSS protection by restricting script sources
- Includes mixed content protection with
upgrade-insecure-requests(production/HTTPS only) - Supports WebSocket protocols (
ws:andwss:) for real-time collaboration - Supports Google Fonts and FontAwesome CDN integration
Important CSP Limitations with Meta Tags:
-
frame-ancestorsdirective is ignored in meta tags (use X-Frame-Options header instead) -
report-uriandreport-todirectives are ignored in meta tags -
sandboxdirective is ignored in meta tags - These directives must be set via HTTP headers at the server/proxy level
Example CSP Generated (frontend meta tag):
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdnjs.cloudflare.com;
font-src 'self' https://fonts.gstatic.com https://cdnjs.cloudflare.com data:;
img-src 'self' data: https: blob:;
connect-src 'self' https://api.example.com wss: ws: https:;
base-uri 'self';
form-action 'self';
object-src 'none';
media-src 'self';
worker-src 'self' blob:;
manifest-src 'self';
upgrade-insecure-requests
Note: The backend API server also sets its own CSP via HTTP headers with a more permissive script-src 'self' 'unsafe-inline' 'unsafe-eval' policy. The frontend and backend CSPs serve different purposes and apply to different responses.
When deploying the TMI-UX frontend behind a reverse proxy (nginx, etc.), these headers must be configured at the proxy level. The TMI backend API already sets these headers automatically via middleware.
| Header | Value | Purpose |
|---|---|---|
| X-Frame-Options |
DENY or SAMEORIGIN
|
Prevents clickjacking (CSP frame-ancestors ignored in meta tags) |
| X-Content-Type-Options | nosniff |
Prevents MIME type sniffing |
| X-XSS-Protection | 0 |
Disable legacy XSS auditor (use CSP instead) |
| Strict-Transport-Security | max-age=31536000; includeSubDomains |
Forces HTTPS (TLS only) |
| Referrer-Policy | strict-origin-when-cross-origin |
Controls referrer information |
| Permissions-Policy | camera=(), microphone=(), geolocation=() |
Disables unused browser APIs |
server {
listen 443 ssl http2;
server_name tmi.example.com;
# Security headers
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "0" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
server_tokens off;
location / {
root /var/www/tmi-ux;
try_files $uri $uri/ /index.html;
}
# WebSocket support for diagram collaboration
location ~ /threat_models/.*/diagrams/.*/ws$ {
proxy_pass http://backend:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# WebSocket support for notifications
location /ws/notifications {
proxy_pass http://backend:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}Use the provided security check script:
pnpm run check:securityOr test online with:
For detailed configuration across all deployment scenarios (standalone, proxy, load balancer, Docker, AWS ALB), see the Security Headers Configuration Guide.
- Configuration-Reference - Secure configuration options
- Setting-Up-Authentication - OAuth setup
- Security-Operations - Container security and TLS management
- Architecture-and-Design - Permission model (RBAC section)
- NIST Cybersecurity Framework
- OWASP Application Security Top 10
- Docker Security Best Practices
- Kubernetes Security Documentation
- OAuth 2.0 Security Best Current Practices
- Using TMI for Threat Modeling
- Accessing TMI
- Authentication
- Creating Your First Threat Model
- Understanding the User Interface
- Working with Data Flow Diagrams
- Managing Threats
- Collaborative Threat Modeling
- Using Notes and Documentation
- Timmy AI Assistant
- Metadata and Extensions
- Planning Your Deployment
- Terraform Deployment (AWS, OCI, GCP, Azure)
- Deploying TMI Server
- OCI Container Deployment
- Certificate Automation
- Deploying TMI Web Application
- Setting Up Authentication
- Database Setup
- Component Integration
- Post-Deployment
- Branding and Customization
- Monitoring and Health
- Cloud Logging
- Database Operations
- Security Operations
- Performance and Scaling
- Maintenance Tasks
- Getting Started with Development
- Architecture and Design
- API Integration
- Testing
- Contributing
- Extending TMI
- Dependency Upgrade Plans
- DFD Graphing Library Reference
- Migration Instructions