Lack of Administrator Control over Security
Description
Lack of Administrator Control over Security occurs when a product does not provide administrators with sufficient control to manage security settings and configurations. This includes hardcoded security policies, inability to change default credentials, missing audit controls, lack of security feature toggles, and absence of granular permission management. Administrators cannot adapt security posture to their organization's needs.
Risk
Organizations cannot enforce security policies. Default credentials remain unchanged. Security features cannot be enabled/disabled as needed. No ability to comply with regulatory requirements. Unable to respond to security incidents. Audit and monitoring gaps. One-size-fits-all security inappropriate for environment.
Solution
Provide comprehensive security configuration interfaces. Allow credential management and rotation. Implement granular role-based access control. Provide security audit logging with configurable levels. Enable/disable security features via configuration. Document all security settings. Support security policy customization.
Common Consequences
| Impact | Details |
|---|---|
| Security | Scope: Inability to Adapt Security cannot be tailored to environment. |
| Compliance | Scope: Regulatory Failure Cannot meet security audit requirements. |
| Operations | Scope: Incident Response Cannot respond effectively to security events. |
Example Code + Solution Code
Vulnerable Code
// VULNERABLE: No administrative security controls
public class VulnerableSecurityConfig {
// VULNERABLE: Hardcoded credentials, no way to change
private static final String ADMIN_USERNAME = "admin";
private static final String ADMIN_PASSWORD = "admin123";
public boolean authenticate(String username, String password) {
// VULNERABLE: Cannot change these credentials
return ADMIN_USERNAME.equals(username) &&
ADMIN_PASSWORD.equals(password);
}
// VULNERABLE: Hardcoded session timeout
private static final int SESSION_TIMEOUT = 3600; // 1 hour, unchangeable
// VULNERABLE: Hardcoded password policy
public boolean isPasswordValid(String password) {
return password.length() >= 6; // Fixed, cannot be strengthened
}
// VULNERABLE: No audit control
public void performAdminAction(String action) {
// No logging, no audit trail
executeAction(action);
}
// VULNERABLE: All-or-nothing permissions
public boolean hasPermission(User user, String resource) {
// Only admin or regular user, no granularity
return user.isAdmin();
}
// VULNERABLE: Security features hardcoded
private boolean mfaEnabled = false; // Cannot be changed
private boolean bruteForceProtection = false; // No way to enable
}
// VULNERABLE: No security configuration API
@RestController
public class VulnerableAdminController {
// No endpoints for:
// - Changing security settings
// - Managing users/roles
// - Viewing audit logs
// - Configuring authentication
}
# VULNERABLE: Python application without security controls
class VulnerableApp:
# VULNERABLE: Hardcoded settings
SECRET_KEY = "hardcoded_secret_key_12345"
ADMIN_PASSWORD = "admin"
# VULNERABLE: No configurable security policies
PASSWORD_MIN_LENGTH = 4 # Fixed, too weak
SESSION_DURATION = 86400 # 24 hours, unchangeable
MAX_LOGIN_ATTEMPTS = None # No rate limiting
def __init__(self):
# VULNERABLE: No way to configure
self.debug_mode = True # Always on
self.ssl_verify = False # Cannot enable
# VULNERABLE: No audit logging configuration
def admin_action(self, action, user):
# No option to log, no severity levels
self.execute(action)
# VULNERABLE: Fixed authentication mechanism
def authenticate(self, username, password):
# No MFA option
# No OAuth/SAML integration
# Single fixed auth method
return self.check_password(username, password)
# VULNERABLE: No role customization
def check_permission(self, user, action):
# Hardcoded roles, cannot create custom ones
return user.role == 'admin'
# VULNERABLE: No security configuration file support
# No way to load security settings from config
# No environment-specific security profiles
// VULNERABLE: Node.js app without security controls
const express = require('express');
const app = express();
// VULNERABLE: Hardcoded security settings
const config = {
jwtSecret: 'hardcoded_jwt_secret', // Cannot change
sessionTimeout: 3600, // Fixed
corsOrigin: '*', // Cannot restrict
rateLimitEnabled: false // Cannot enable
};
// VULNERABLE: No way to modify security headers
app.use((req, res, next) => {
// Hardcoded headers, not configurable
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
// Admin cannot change to DENY
next();
});
// VULNERABLE: Fixed authentication
class VulnerableAuth {
constructor() {
// No configuration options
this.hashRounds = 10; // Fixed
this.tokenExpiry = '1h'; // Fixed
this.mfaEnabled = false; // Cannot enable
}
// No admin methods for:
// - Changing security settings
// - Managing API keys
// - Viewing security logs
// - Configuring rate limits
}
// VULNERABLE: No security dashboard or management UI
// VULNERABLE: No API for security configuration
// VULNERABLE: No audit log access
<?php
// VULNERABLE: PHP application without admin controls
class VulnerableConfig {
// VULNERABLE: Hardcoded security constants
const ADMIN_USER = 'admin';
const ADMIN_PASS = 'password123';
const SESSION_LIFETIME = 3600;
const PASSWORD_ALGO = PASSWORD_DEFAULT;
const MIN_PASSWORD_LENGTH = 4;
// No way to change any of these at runtime
// No admin interface to modify
}
// VULNERABLE: No configurable security features
class VulnerableSecurityManager {
private $features = [
'csrf_protection' => true, // Hardcoded
'xss_filtering' => false, // Cannot enable
'sql_escaping' => true,
'rate_limiting' => false, // Cannot enable
'ip_blocking' => false, // Cannot enable
];
// No setters, no admin interface
public function isEnabled($feature) {
return $this->features[$feature] ?? false;
}
// VULNERABLE: No audit capabilities
public function logSecurityEvent($event) {
// Logging is hardcoded off, no way to enable
// No log level configuration
// No log destination options
}
}
// VULNERABLE: No user/role management
class VulnerableUserManager {
// Hardcoded roles
private $roles = ['admin', 'user']; // Cannot add custom roles
// Hardcoded permissions
private $permissions = [
'admin' => ['*'],
'user' => ['read']
];
// Cannot modify, no RBAC interface
}
?>
Fixed Code
// SAFE: Comprehensive administrative security controls
@Configuration
public class SecureSecurityConfig {
@Value("${security.session.timeout:3600}")
private int sessionTimeout;
@Value("${security.password.minLength:12}")
private int minPasswordLength;
@Value("${security.mfa.enabled:false}")
private boolean mfaEnabled;
@Value("${security.bruteforce.protection:true}")
private boolean bruteForceProtection;
// SAFE: Credentials from secure configuration
@Value("${admin.password.hash}")
private String adminPasswordHash;
// SAFE: Configurable password policy
@Bean
public PasswordPolicy passwordPolicy() {
return PasswordPolicy.builder()
.minLength(minPasswordLength)
.requireUppercase(configService.getBoolean("password.requireUppercase", true))
.requireNumber(configService.getBoolean("password.requireNumber", true))
.requireSpecial(configService.getBoolean("password.requireSpecial", false))
.build();
}
}
// SAFE: Admin security management API
@RestController
@RequestMapping("/admin/security")
@PreAuthorize("hasRole('SECURITY_ADMIN')")
public class SecurityAdminController {
@Autowired
private SecurityConfigService securityConfigService;
@Autowired
private AuditService auditService;
// SAFE: Update security settings
@PutMapping("/settings")
public ResponseEntity<?> updateSecuritySettings(@RequestBody SecuritySettings settings) {
auditService.log("SECURITY_SETTINGS_CHANGE", settings);
securityConfigService.update(settings);
return ResponseEntity.ok().build();
}
// SAFE: Configure password policy
@PutMapping("/password-policy")
public ResponseEntity<?> updatePasswordPolicy(@RequestBody PasswordPolicy policy) {
auditService.log("PASSWORD_POLICY_CHANGE", policy);
securityConfigService.updatePasswordPolicy(policy);
return ResponseEntity.ok().build();
}
// SAFE: Enable/disable MFA
@PostMapping("/mfa/toggle")
public ResponseEntity<?> toggleMFA(@RequestParam boolean enabled) {
auditService.log("MFA_TOGGLE", enabled);
securityConfigService.setMFAEnabled(enabled);
return ResponseEntity.ok().build();
}
// SAFE: View security audit logs
@GetMapping("/audit")
public ResponseEntity<List<AuditEvent>> getAuditLogs(
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate,
@RequestParam(required = false) String eventType) {
return ResponseEntity.ok(auditService.query(startDate, endDate, eventType));
}
// SAFE: Manage security features
@GetMapping("/features")
public ResponseEntity<Map<String, Boolean>> getSecurityFeatures() {
return ResponseEntity.ok(securityConfigService.getAllFeatures());
}
@PutMapping("/features/{feature}")
public ResponseEntity<?> toggleFeature(
@PathVariable String feature,
@RequestParam boolean enabled) {
auditService.log("FEATURE_TOGGLE", feature + ":" + enabled);
securityConfigService.setFeature(feature, enabled);
return ResponseEntity.ok().build();
}
}
// SAFE: Role-based access control management
@RestController
@RequestMapping("/admin/rbac")
public class RBACAdminController {
@PostMapping("/roles")
public ResponseEntity<?> createRole(@RequestBody Role role) {
return ResponseEntity.ok(rbacService.createRole(role));
}
@PutMapping("/roles/{roleId}/permissions")
public ResponseEntity<?> updatePermissions(
@PathVariable Long roleId,
@RequestBody List<Permission> permissions) {
return ResponseEntity.ok(rbacService.updatePermissions(roleId, permissions));
}
}
# SAFE: Python with comprehensive admin controls
from dataclasses import dataclass
from typing import Dict, Any, Optional
import yaml
@dataclass
class SecuritySettings:
session_timeout: int = 3600
password_min_length: int = 12
password_require_uppercase: bool = True
password_require_number: bool = True
password_require_special: bool = True
mfa_enabled: bool = False
rate_limiting_enabled: bool = True
max_login_attempts: int = 5
lockout_duration: int = 900
audit_level: str = 'INFO'
class SecurityConfigService:
def __init__(self, config_path: str = '/etc/app/security.yaml'):
self.config_path = config_path
self.settings = self._load_settings()
self.audit_logger = AuditLogger()
def _load_settings(self) -> SecuritySettings:
"""Load settings from config file"""
try:
with open(self.config_path) as f:
config = yaml.safe_load(f)
return SecuritySettings(**config.get('security', {}))
except FileNotFoundError:
return SecuritySettings()
def update_setting(self, key: str, value: Any, admin_user: str):
"""Admin can update any security setting"""
old_value = getattr(self.settings, key, None)
# Audit the change
self.audit_logger.log(
event='SECURITY_SETTING_CHANGE',
user=admin_user,
details={
'setting': key,
'old_value': old_value,
'new_value': value
}
)
setattr(self.settings, key, value)
self._save_settings()
def _save_settings(self):
"""Persist settings to config file"""
with open(self.config_path, 'w') as f:
yaml.dump({'security': asdict(self.settings)}, f)
def get_all_settings(self) -> Dict[str, Any]:
"""Get all settings for admin UI"""
return asdict(self.settings)
# SAFE: Admin API for security management
from flask import Flask, request, jsonify
from functools import wraps
app = Flask(__name__)
security_service = SecurityConfigService()
def require_security_admin(f):
@wraps(f)
def decorated(*args, **kwargs):
user = get_current_user()
if not user.has_role('SECURITY_ADMIN'):
return jsonify({'error': 'Forbidden'}), 403
return f(*args, **kwargs)
return decorated
@app.route('/admin/security/settings', methods=['GET'])
@require_security_admin
def get_security_settings():
"""Get all security settings"""
return jsonify(security_service.get_all_settings())
@app.route('/admin/security/settings/<key>', methods=['PUT'])
@require_security_admin
def update_security_setting(key):
"""Update a security setting"""
value = request.json.get('value')
admin_user = get_current_user().username
security_service.update_setting(key, value, admin_user)
return jsonify({'success': True})
@app.route('/admin/security/audit', methods=['GET'])
@require_security_admin
def get_audit_logs():
"""Query security audit logs"""
start = request.args.get('start')
end = request.args.get('end')
event_type = request.args.get('type')
logs = audit_service.query(start, end, event_type)
return jsonify(logs)
@app.route('/admin/security/features', methods=['GET', 'PUT'])
@require_security_admin
def manage_features():
"""Manage security feature toggles"""
if request.method == 'GET':
return jsonify(security_service.get_features())
else:
feature = request.json.get('feature')
enabled = request.json.get('enabled')
security_service.toggle_feature(feature, enabled, get_current_user())
return jsonify({'success': True})
# SAFE: Role and permission management
@app.route('/admin/rbac/roles', methods=['GET', 'POST'])
@require_security_admin
def manage_roles():
if request.method == 'GET':
return jsonify(rbac_service.get_all_roles())
else:
role = request.json
created = rbac_service.create_role(role)
return jsonify(created), 201
// SAFE: Node.js with admin security controls
const express = require('express');
const fs = require('fs');
const yaml = require('js-yaml');
class SecurityConfigService {
constructor(configPath = '/etc/app/security.yaml') {
this.configPath = configPath;
this.settings = this.loadSettings();
this.auditLogger = new AuditLogger();
}
loadSettings() {
try {
const config = yaml.load(fs.readFileSync(this.configPath));
return {
sessionTimeout: config.session?.timeout ?? 3600,
passwordMinLength: config.password?.minLength ?? 12,
mfaEnabled: config.mfa?.enabled ?? false,
rateLimitEnabled: config.rateLimit?.enabled ?? true,
maxLoginAttempts: config.rateLimit?.maxAttempts ?? 5,
corsOrigins: config.cors?.origins ?? [],
auditLevel: config.audit?.level ?? 'INFO',
...config
};
} catch (e) {
return this.getDefaultSettings();
}
}
updateSetting(key, value, adminUser) {
const oldValue = this.settings[key];
this.auditLogger.log({
event: 'SECURITY_SETTING_CHANGE',
user: adminUser,
setting: key,
oldValue,
newValue: value
});
this.settings[key] = value;
this.saveSettings();
}
saveSettings() {
fs.writeFileSync(this.configPath, yaml.dump(this.settings));
}
getAllSettings() {
return { ...this.settings };
}
}
// SAFE: Admin security API
const router = express.Router();
const securityService = new SecurityConfigService();
// Middleware for security admin check
const requireSecurityAdmin = (req, res, next) => {
if (!req.user?.hasRole('SECURITY_ADMIN')) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
router.use(requireSecurityAdmin);
// Get all security settings
router.get('/settings', (req, res) => {
res.json(securityService.getAllSettings());
});
// Update security setting
router.put('/settings/:key', (req, res) => {
const { key } = req.params;
const { value } = req.body;
securityService.updateSetting(key, value, req.user.username);
res.json({ success: true });
});
// Manage security features
router.get('/features', (req, res) => {
res.json(securityService.getFeatures());
});
router.put('/features/:feature', (req, res) => {
const { feature } = req.params;
const { enabled } = req.body;
securityService.toggleFeature(feature, enabled, req.user);
res.json({ success: true });
});
// Query audit logs
router.get('/audit', async (req, res) => {
const { start, end, type } = req.query;
const logs = await auditService.query(start, end, type);
res.json(logs);
});
// RBAC management
router.get('/roles', (req, res) => {
res.json(rbacService.getAllRoles());
});
router.post('/roles', (req, res) => {
const role = rbacService.createRole(req.body);
res.status(201).json(role);
});
router.put('/roles/:roleId/permissions', (req, res) => {
rbacService.updatePermissions(req.params.roleId, req.body.permissions);
res.json({ success: true });
});
module.exports = router;
Exploited in the Wild
Hardcoded Credentials
Default passwords that cannot be changed exploited at scale.
Compliance Failures
Organizations failing audits due to inflexible security.
Incident Response Gaps
Unable to respond to breaches due to missing controls.
Tools to test/exploit
-
Security configuration scanners.
-
Compliance audit tools.
-
Default credential scanners.
CVE Examples
-
Numerous CVEs from hardcoded credentials.
-
IoT devices with unchangeable passwords.
References
-
MITRE. "CWE-671: Lack of Administrator Control over Security." https://cwe.mitre.org/data/definitions/671.html
-
NIST security configuration guidelines.