CWE-749: Exposed Dangerous Method or Function
Overview
Exposed dangerous methods (admin functions, debug endpoints, internal APIs, privileged operations) accessible without proper authorization enable attackers to invoke sensitive functionality directly, bypassing normal access controls and security checks.
OWASP Classification
A01:2025 - Broken Access Control
Risk
Critical: Exposed dangerous methods enable direct invocation of admin functions, database operations, file system access, code execution, configuration changes, and user impersonation without authentication/authorization checks.
Remediation Strategy
Make Methods Private/Internal (Primary Defense)
# VULNERABLE - public dangerous method
class UserController:
def delete_all_users(self): # Public!
db.execute("DELETE FROM users")
return {"deleted": "all users"}
# Attacker: POST /api/users/delete_all_users
# SECURE - private method with authorization
class UserController:
@require_authentication
@require_role('SUPER_ADMIN')
@audit_log
def delete_user(self, user_id):
# Can only delete one user at a time
# Requires authentication and authorization
if not self._validate_delete(user_id):
raise PermissionError()
user = User.query.get_or_404(user_id)
db.session.delete(user)
db.session.commit()
def _validate_delete(self, user_id):
# Internal helper - not exposed
return user_id != current_user.id
Remove Debug/Admin Endpoints from Production
# VULNERABLE - debug endpoint in production
@app.route('/admin/execute_sql')
def execute_sql():
query = request.args.get('query')
result = db.execute(query) # SQL injection + exposed!
return jsonify(result)
# SECURE - remove entirely or protect
import os
if os.getenv('ENVIRONMENT') == 'development':
@app.route('/dev/debug')
@require_local_access # Only from localhost
@require_dev_token
def debug_endpoint():
# Only available in dev
return {"debug": get_debug_info()}
Implement Proper Access Controls
// VULNERABLE - no access control
@RestController
public class AdminController {
@PostMapping("/api/admin/grant-admin")
public Response grantAdmin(@RequestParam Long userId) {
// Anyone can call this!
userService.setRole(userId, Role.ADMIN);
return Response.ok();
}
}
// SECURE - proper authorization
@RestController
@RequestMapping("/api/admin")
@PreAuthorize("hasRole('SUPER_ADMIN')")
public class AdminController {
@PostMapping("/grant-admin")
@PreAuthorize("#userId != authentication.principal.id") // Can't self-promote
@AuditLog(action = "GRANT_ADMIN")
public Response grantAdmin(
@RequestParam Long userId,
@AuthenticationPrincipal User currentUser) {
// Additional validation
if (!canGrantAdminTo(currentUser, userId)) {
throw new AccessDeniedException();
}
userService.setRole(userId, Role.ADMIN);
return Response.ok();
}
}
Use Allowlists for Exposed Functions
// VULNERABLE - dynamic method invocation
app.post('/api/invoke', (req, res) => {
const method = req.body.method;
const args = req.body.args;
// Attacker can call ANY method!
const result = controller[method](...args);
res.json(result);
});
// SECURE - allowlist of safe methods
const ALLOWED_METHODS = new Set([
'getUserProfile',
'updateProfile',
'changePassword'
]);
app.post('/api/invoke', authenticate, (req, res) => {
const method = req.body.method;
if (!ALLOWED_METHODS.has(method)) {
return res.status(403).json({error: 'Method not allowed'});
}
// Additional authorization check
if (!canInvoke(req.user, method)) {
return res.status(403).json({error: 'Unauthorized'});
}
const result = controller[method](req.user, req.body.args);
res.json(result);
});
Remediation Steps
Core principle: Do not expose dangerous functionality to untrusted actors; gate high-risk operations behind strong controls.
- Identify exposed dangerous methods
- Determine exposure paths
- Check authorization gaps
- Make methods private/internal: Change visibility modifiers, remove from public API, move to internal classes
- Add access controls: Require authentication tokens, verify user roles, implement permission checks before execution
- Test unauthorized access: Attempt to invoke dangerous methods without proper credentials (should return 401/403)
- Audit all exposed endpoints: Review entire API surface to identify other potentially dangerous methods
Common Exposed Dangerous Methods
Admin Functions:
# Exposed without auth
@app.route('/admin/reset_database')
def reset_database():
db.drop_all()
db.create_all()
@app.route('/admin/set_config')
def set_config():
key = request.args['key']
value = request.args['value']
config[key] = value
File Operations:
@GetMapping("/files/delete")
public void deleteFile(@RequestParam String path) {
new File(path).delete(); // Anyone can delete any file!
}
Code Execution:
@app.route('/eval')
def evaluate():
code = request.args.get('code')
return str(eval(code)) # Remote code execution!
Direct Database Access:
<?php
// Direct SQL execution endpoint
if ($_GET['action'] == 'query') {
$result = mysqli_query($conn, $_GET['sql']);
echo json_encode(mysqli_fetch_all($result));
}