iHub Apps implements a comprehensive security model designed to protect user data, secure API communications, and provide flexible authentication and authorization. This guide covers security best practices for deployment, configuration, and operation.
- Security Architecture Overview
- Authentication & Authorization
- API Security
- LLM Integration Security
- Data Protection
- Network Security
- Deployment Security
- Operational Security
- Security Checklist
- Compliance & Standards
iHub Apps follows these security principles:
- Defense in Depth: Multiple layers of security controls
- Least Privilege: Users and services have minimal necessary permissions
- Zero Trust: No implicit trust, verify everything
- Secure by Default: Secure configurations out of the box
- Transparency: Clear logging and audit trails
┌─────────────────────────────────────────┐
│ Client Layer │
├─────────────────────────────────────────┤
│ Network Security │
│ (CORS, HTTPS, Headers) │
├─────────────────────────────────────────┤
│ Authentication Layer │
│ (OIDC, Local, Proxy, LDAP) │
├─────────────────────────────────────────┤
│ Authorization Layer │
│ (Group-based, Resource Filtering) │
├─────────────────────────────────────────┤
│ Application Layer │
│ (Input Validation, Rate Limiting) │
├─────────────────────────────────────────┤
│ Data Layer │
│ (Encryption, Access Control) │
├─────────────────────────────────────────┤
│ Infrastructure Layer │
│ (Container Security, Secrets) │
└─────────────────────────────────────────┘
iHub Apps supports multiple authentication modes that can be configured in contents/config/platform.json:
{
"auth": {
"mode": "local"
},
"localAuth": {
"enabled": true,
"usersFile": "contents/config/users.json",
"showDemoAccounts": false
}
}Security Considerations:
- Use strong passwords (minimum 12 characters)
- Enable password hashing with bcryptjs (default)
- Disable demo accounts in production
- Store user credentials securely
{
"auth": {
"mode": "oidc"
},
"oidcAuth": {
"enabled": true,
"allowSelfSignup": false,
"providers": [{
"name": "corporate-sso",
"issuer": "https://identity.company.com",
"clientId": "your-client-id",
"clientSecret": "${OIDC_CLIENT_SECRET}"
}]
}
}Security Best Practices:
- Always use HTTPS for OIDC endpoints
- Store client secrets as environment variables
- Disable self-signup for production
- Use short session timeouts
- Implement proper logout flows
{
"auth": {
"mode": "proxy"
},
"proxyAuth": {
"enabled": true,
"userHeader": "X-Forwarded-User",
"groupsHeader": "X-Forwarded-Groups",
"jwksUrl": "https://auth-server.company.com/.well-known/jwks"
}
}Security Requirements:
- Ensure proxy strips user headers from client requests
- Validate JWT signatures using JWKS
- Use trusted reverse proxy (nginx, Apache, etc.)
- Implement proper header validation
{
"anonymousAuth": {
"enabled": true,
"defaultGroups": ["anonymous"]
}
}Security Warnings:
- Only enable for public demos or specific use cases
- Heavily restrict anonymous user permissions
- Monitor usage for abuse
- Consider rate limiting
iHub Apps uses a hierarchical group inheritance system:
{
"groups": {
"admin": {
"id": "admin",
"inherits": ["users"],
"permissions": {
"apps": ["*"],
"models": ["*"],
"prompts": ["*"],
"adminAccess": true
}
},
"users": {
"id": "users",
"inherits": ["authenticated"],
"permissions": {
"apps": ["chat", "analysis"],
"models": ["gpt-4", "claude-3"],
"prompts": ["general"]
}
},
"authenticated": {
"id": "authenticated",
"inherits": ["anonymous"],
"permissions": {
"apps": ["chat"],
"models": ["gpt-3.5-turbo"]
}
}
}
}Security Features:
- Circular dependency detection
- Permission inheritance and merging
- Resource-level access control
- Wildcard and specific permissions
All resources are filtered based on user permissions:
// Example: Only shows models user has access to
const userModels = filterResourcesByPermissions(
allModels,
user.permissions.models
);{
"auth": {
"sessionTimeoutMinutes": 480,
"jwtSecret": "${JWT_SECRET}"
}
}Best Practices:
- Use strong JWT secrets (32+ characters)
- Implement session timeout
- Rotate JWT secrets regularly
- Use secure cookie settings
- Bcryptjs hashing with salt rounds
- Password complexity requirements
- Account lockout policies
- Secure password reset flows
// Configurable request size limits
export function checkContentLength(limit) {
return (req, res, next) => {
const length = parseInt(req.headers['content-length'], 10);
if (!Number.isNaN(length) && length > limit) {
return res.status(413).send('Payload Too Large');
}
next();
};
}Configuration:
{
"requestBodyLimitMB": 50
}All user inputs are validated and sanitized:
- JSON schema validation
- XSS prevention
- SQL injection protection
- Path traversal prevention
export function authRequired(req, res, next) {
if (!isAnonymousAccessAllowed(platformConfig)) {
if (!req.user || req.user.id === 'anonymous') {
return res.status(401).json({
error: 'Authentication required',
code: 'AUTH_REQUIRED'
});
}
}
next();
}export const appAccessRequired = resourceAccessRequired('app');
export const modelAccessRequired = resourceAccessRequired('model');{
"requestConcurrency": 5
}Implementation:
- Per-user request limiting
- Global concurrency controls
- Request throttling for expensive operations
- Graceful degradation under load
export async function getApiKeyForModel(modelId) {
const provider = model.provider;
switch (provider) {
case 'openai':
return config.OPENAI_API_KEY;
case 'anthropic':
return config.ANTHROPIC_API_KEY;
// ... other providers
}
}Security Requirements:
- Store API keys as environment variables only
- Never hardcode API keys in configuration files
- Use different keys for different environments
- Rotate API keys regularly
# Production environment
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
export GOOGLE_API_KEY="AIza..."
export MISTRAL_API_KEY="..."
# Optional: Default fallback key
export DEFAULT_API_KEY="fallback-key"class ApiKeyVerifier {
async verifyApiKey(model, res, clientRes, language) {
const apiKey = await getApiKeyForModel(model.id);
if (!apiKey) {
console.error(`API key not found for model: ${model.id}`);
// Return localized error without exposing system details
return { success: false, error };
}
return { success: true, apiKey };
}
}- All LLM API requests use HTTPS
- Proper certificate validation
- Request signing where available
- Timeout configuration
- Content filtering for malicious responses
- Response size limits
- Error message sanitization
- No sensitive data in logs
For custom or local LLM endpoints:
{
"models": [{
"id": "custom-llm",
"provider": "local",
"endpoint": "https://internal-llm.company.com",
"requiresApiKey": false
}]
}Security Considerations:
- Use internal network isolation
- Implement proper certificate validation
- Consider VPN or private networking
- Monitor for unusual traffic patterns
- Public: App configurations, public documentation
- Internal: Usage analytics, system metrics
- Confidential: User messages, authentication data
- Restricted: API keys, system secrets
- All external communications use TLS 1.2+
- Internal communications encrypted in production
- Certificate validation enforced
- HSTS headers implemented
- Configuration files protected by filesystem permissions
- User data stored with appropriate access controls
- Logs rotated and archived securely
- Backup encryption recommended
- Integration secrets encrypted in
platform.jsonusing AES-256-GCM (see Secret Encryption at Rest below)
Platform configuration secrets (Jira, OIDC, LDAP, NTLM, Cloud Storage) are automatically encrypted on disk using TokenStorageService with AES-256-GCM authenticated encryption. This means even if platform.json is read by an unauthorized party, the raw secret values are not exposed.
Encrypted values use a self-describing format that is easy to identify:
ENC[AES256_GCM,data:<base64>,iv:<base64>,tag:<base64>,type:str]
The format encodes the algorithm, encrypted data, initialization vector, authentication tag, and value type. This makes encrypted values unambiguous and allows safe co-existence with plaintext or environment variable placeholder values.
The AES-256 encryption key is stored at contents/.encryption-key with mode 0600 (owner read/write only). If the file does not exist at startup, a new key is generated automatically and persisted.
Important: Back up this file securely. Losing it makes all encrypted secrets in platform.json unrecoverable without re-entering them through the admin interface.
The key path can be overridden by setting the TOKEN_ENCRYPTION_KEY environment variable, which is required for multi-node deployments to ensure all nodes share the same key.
The following fields in platform.json are encrypted at rest:
| Config Section | Field |
|---|---|
jira |
clientSecret |
cloudStorage.providers[] (type: office365) |
clientSecret, tenantId |
cloudStorage.providers[] (type: googledrive) |
clientSecret |
oidcAuth.providers[] |
clientSecret |
ldapAuth.providers[] |
adminPassword |
ntlmAuth |
domainControllerPassword |
iFinder |
privateKey |
- On admin save (
POST /api/admin/configs/platform): Secrets are encrypted before writing toplatform.json - On admin read (
GET /api/admin/configs/platform): Secrets are decrypted, then sanitized to***REDACTED***before being returned to the browser - At runtime (
configCache.js): Secrets are decrypted when the platform config is loaded into the in-memory cache so all consumers receive plaintext values
The encryption logic uses the following guard pattern to prevent double-encryption and to skip environment variable placeholders:
function encryptIfNeeded(value) {
if (!value || typeof value !== 'string') return value;
// Skip environment variable placeholders like ${MY_SECRET}
if (/^\$\{[^}]+\}$/.test(value)) return value;
// Skip already-encrypted values
if (tokenStorageService.isEncrypted(value)) return value;
return tokenStorageService.encryptString(value);
}Plaintext secrets already present in platform.json are passed through unchanged on read. They are encrypted automatically the next time an admin saves the platform configuration (lazy migration). No migration script is required.
server/services/TokenStorageService.js—encryptString(),decryptString(),isEncrypted()server/routes/admin/configs.js—encryptPlatformSecrets(),decryptPlatformSecrets(),encryptIfNeeded(),decryptIfNeeded()server/configCache.js—decryptPlatformSecrets()applied during platform config loading
// File type and size validation
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
const maxSize = 10 * 1024 * 1024; // 10MB
if (!allowedTypes.includes(file.mimetype)) {
throw new Error('Invalid file type');
}- Files stored outside web root
- Virus scanning integration recommended
- Access logging for uploaded files
- Automatic cleanup of temporary files
- Messages encrypted in memory during processing
- No long-term storage of conversation content by default
- Audit logging for sensitive operations
- Automatic cleanup of inactive sessions
- Users can delete conversation history
- Admin cannot access user conversations by default
- Export controls for conversation data
- GDPR compliance features available
{
"cors": {
"origin": ["http://localhost:3000", "http://localhost:5173"],
"credentials": true,
"methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
"allowedHeaders": [
"Content-Type",
"Authorization",
"X-Requested-With"
]
}
}{
"cors": {
"origin": ["https://yourdomain.com"],
"credentials": true,
"maxAge": 86400,
"preflightContinue": false
}
}Environment Variable Support:
{
"cors": {
"origin": ["${ALLOWED_ORIGINS}"]
}
}# Multiple origins
export ALLOWED_ORIGINS="https://app1.company.com,https://app2.company.com"# Environment variables for SSL
export SSL_CERT=/path/to/certificate.pem
export SSL_KEY=/path/to/private-key.pem
export SSL_CA=/path/to/ca-certificate.pem # Optional- Use TLS 1.2 or higher
- Implement HSTS headers
- Use strong cipher suites
- Regular certificate rotation
- Monitor certificate expiration
For internal deployments, see SSL Certificates Guide:
# Secure method - import to system trust store
sudo cp internal-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
# Alternative - Node.js specific
export NODE_EXTRA_CA_CERTS=/path/to/certificates.pemserver {
listen 443 ssl;
server_name ihub.company.com;
ssl_certificate /path/to/certificate.pem;
ssl_certificate_key /path/to/private-key.pem;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# For proxy authentication
proxy_set_header X-Forwarded-User $remote_user;
proxy_set_header X-Forwarded-Groups $groups;
}
}# UFW example - restrict to necessary ports
sudo ufw allow 22/tcp # SSH
sudo ufw allow 443/tcp # HTTPS
sudo ufw allow from 10.0.0.0/8 to any port 3000 # Internal access only
sudo ufw enable# Set production environment
export NODE_ENV=production
# Remove development dependencies
npm ci --only=production
# Set secure file permissions
chmod 600 .env
chmod -R 644 contents/config/
chmod 755 contents/
# Run as non-root user
useradd -r -s /bin/false ihub
chown -R ihub:ihub /opt/ihub-apps
sudo -u ihub npm run start:prod# Using systemd (recommended)
sudo systemctl enable ihub-apps
sudo systemctl start ihub-apps
# Monitor service status
sudo systemctl status ihub-apps# Multi-stage build reduces attack surface
FROM node:20-alpine AS production
# Run as non-root user
RUN addgroup -S ihub && adduser -S -D -H -s /sbin/nologin -G ihub ihub
USER ihub
# Use tini for proper signal handling
ENTRYPOINT ["/sbin/tini", "--"]
# Health checks
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD node /app/healthcheck.js- Use official base images
- Regular security updates
- Minimal image layers
- Non-root user execution
- Read-only filesystems where possible
- Resource limits
services:
ihub-app:
image: ihub-apps:latest
volumes:
# Configuration as read-only
- ihub-config:/app/contents/config:ro
- ihub-apps:/app/contents/apps:ro
# Writable data volumes
- ihub-data:/app/contents/data:rw
- ihub-logs:/app/logs:rw
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '3'
restart: unless-stoppedapiVersion: apps/v1
kind: Deployment
metadata:
name: ihub-apps
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: ihub-apps
image: ihub-apps:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
limits:
cpu: 2
memory: 2Gi
requests:
cpu: 500m
memory: 512MiapiVersion: v1
kind: Secret
metadata:
name: ihub-secrets
type: Opaque
stringData:
OPENAI_API_KEY: "sk-..."
JWT_SECRET: "your-jwt-secret"
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: ihub-apps
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: ihub-secrets
key: OPENAI_API_KEY# Download and verify checksums
wget https://releases.example.com/ihub-apps-v1.0.0-linux
wget https://releases.example.com/ihub-apps-v1.0.0-linux.sha256
# Verify integrity
sha256sum -c ihub-apps-v1.0.0-linux.sha256
# Set secure permissions
chmod 755 ihub-apps-v1.0.0-linux
chown root:root ihub-apps-v1.0.0-linux
# Run as non-root user
sudo -u ihub ./ihub-apps-v1.0.0-linux{
"authDebug": {
"enabled": true,
"maskTokens": true,
"redactPasswords": true,
"consoleLogging": false,
"includeRawData": false
}
}- Automatic token and password redaction
- Structured logging format
- Configurable log levels
- Log rotation and archival
- No sensitive data in logs
- Failed authentication attempts
- Unusual access patterns
- API rate limit violations
- SSL certificate expiration
- Resource usage anomalies
- Error rate increases
- Authentication Failures: Multiple failed logins, account lockouts
- Authorization Violations: Access to restricted resources
- Input Attacks: XSS, SQL injection attempts
- Resource Abuse: Rate limiting violations, unusual usage
- System Compromise: Unauthorized access, data breaches
- Detection: Automated alerts and monitoring
- Analysis: Log review and impact assessment
- Containment: Temporary restrictions or blocks
- Eradication: Fix vulnerabilities, update configurations
- Recovery: Restore normal operations
- Lessons Learned: Update security measures
# Automated backup script
#!/bin/bash
DATE=$(date +%Y%m%d-%H%M%S)
tar -czf "backup-${DATE}.tar.gz" \
contents/config/ \
contents/apps/ \
contents/models/ \
.env
# Encrypt backup
gpg --cipher-algo AES256 --compress-algo 1 --symmetric \
--output "backup-${DATE}.tar.gz.gpg" \
"backup-${DATE}.tar.gz"- Regular restore testing
- Documented recovery procedures
- RTO/RPO requirements
- Alternative deployment strategies
- Monitoring: Subscribe to security advisories
- Assessment: Evaluate impact and urgency
- Testing: Test updates in staging environment
- Deployment: Deploy during maintenance windows
- Verification: Confirm successful update and functionality
# Check for security vulnerabilities
npm audit
# Update dependencies
npm update
# Check for outdated packages
npm outdated- Authentication mode configured (not anonymous for production)
- Strong JWT secret configured (32+ characters)
- User permissions properly configured
- Admin access restricted to necessary users
- Demo accounts disabled
- Session timeout configured appropriately
- Request size limits configured
- Rate limiting enabled
- Input validation implemented
- Error messages don't leak sensitive information
- CORS origins restricted to production domains
- HTTPS enabled with valid certificates
- Security headers configured
- Firewall rules configured
- Internal services not exposed publicly
- Network segmentation implemented
- API keys stored as environment variables
- No secrets in configuration files
- File upload restrictions configured
- Logs don't contain sensitive data
- Data retention policies implemented
- Running as non-root user
- Minimal attack surface (remove unnecessary services)
- Resource limits configured
- Health checks implemented
- Monitoring and alerting configured
- Monitor security alerts and logs
- Check service health and availability
- Review authentication failures
- Review access logs for anomalies
- Check certificate expiration dates
- Update security patches
- Review user access permissions
- Audit configuration changes
- Test backup and recovery procedures
- Security training for team members
- Security assessment and penetration testing
- Update incident response procedures
- Review and update security policies
- Rotate secrets and credentials
- User consent management
- Data portability (export conversations)
- Right to deletion (clear conversation history)
- Data processing transparency
- Breach notification procedures
// Example: User data deletion
async function deleteUserData(userId) {
// Delete conversations
await conversationService.deleteByUser(userId);
// Delete user profile
await userService.delete(userId);
// Audit log
auditLogger.log('user_data_deleted', { userId });
}- Information security management system
- Risk assessment and treatment
- Security controls implementation
- Continuous improvement process
- Security controls documentation
- Access controls and monitoring
- Data encryption and protection
- Incident response procedures
- Vendor risk management
# Audit admin API endpoints for security issues
npm run security:audit
# Scan npm dependencies for vulnerabilities
npm audit
docker scan ihub-apps:latest- Automated compliance reports
- Access control matrices
- Security control effectiveness
- Vulnerability assessment reports
- SSL Certificates Guide - Detailed SSL/TLS configuration
- External Authentication - OIDC and enterprise auth setup
- Server Configuration - Production server configuration
- JWT Authentication - JWT implementation details
For security-related questions or to report security vulnerabilities:
- General Security Questions: Consult this documentation and configuration guides
- Security Vulnerabilities: Report through secure channels following responsible disclosure
- Enterprise Security: Contact your security team for organization-specific guidance
- Compliance Questions: Consult with legal and compliance teams
Remember: Security is an ongoing process, not a one-time configuration. Regular reviews, updates, and monitoring are essential for maintaining a secure deployment.