mirror of
https://github.com/myronblair/novacpx
synced 2026-06-30 17:50:41 -05:00
fix: all code review security findings
- CORS: replace open regex with explicit hostname allowlist + port whitelist - Exception handler: only expose RuntimeException/InvalidArgumentException messages; PDOException and others return generic 'internal error' - Auth::portalUrl(): allowlist-validate HTTP_HOST before using it in redirect URL — prevents open redirect via Host header injection - _branding.php custom_css: strip HTML tags, js: URLs, @import, expression() instead of just </style> which was trivially bypassable - accounts create: check accounts table as well as users for username uniqueness (TOCTOU fix); wrap user INSERT + provisioning in single transaction so rollback is atomic on failure Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LP9Q4kfCAYAjJnsbHBrViZ
This commit is contained in:
+16
-3
@@ -13,7 +13,11 @@ header('Content-Type: application/json');
|
||||
// Global exception handler — prevents uncaught exceptions from crashing PHP-FPM (502)
|
||||
set_exception_handler(function (Throwable $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'message' => $e->getMessage(), 'errors' => []]);
|
||||
// Never expose internal exception messages (may contain SQL, paths, credentials)
|
||||
$safe = ($e instanceof \InvalidArgumentException || $e instanceof \RuntimeException)
|
||||
? $e->getMessage()
|
||||
: 'An internal error occurred.';
|
||||
echo json_encode(['success' => false, 'message' => $safe, 'errors' => []]);
|
||||
exit;
|
||||
});
|
||||
|
||||
@@ -22,9 +26,18 @@ $_ver = file_get_contents(NOVACPX_ROOT . '/VERSION')
|
||||
?: '1.0.0';
|
||||
header('X-NovaCPX-Version: ' . trim($_ver));
|
||||
|
||||
// CORS for same-origin panel requests (ports 8880/8881/8882/8883 and HTTPS via reverse proxy on 443)
|
||||
// CORS — only allow same-host origins on the panel ports or the known proxy hostnames
|
||||
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
||||
if (preg_match('#^https?://[^/]+(:(888[0-3]))?$#', $origin)) {
|
||||
$_allowedHosts = ['novacpx.orbishosting.com', 'admin.novacpx.orbishosting.com',
|
||||
'reseller.novacpx.orbishosting.com', 'panel.novacpx.orbishosting.com',
|
||||
'web.orbishosting.com'];
|
||||
$_originHost = parse_url($origin, PHP_URL_HOST) ?? '';
|
||||
$_originPort = (int)(parse_url($origin, PHP_URL_PORT) ?? 0);
|
||||
$_panelPorts = [PORT_USER ?? 8880, PORT_RESELLER ?? 8881, PORT_ADMIN ?? 8882, PORT_WEBMAIL ?? 8883];
|
||||
if ($origin && (
|
||||
in_array($_originHost, $_allowedHosts, true) ||
|
||||
(in_array($_originPort, $_panelPorts, true) && filter_var($_originHost, FILTER_VALIDATE_IP))
|
||||
)) {
|
||||
header("Access-Control-Allow-Origin: $origin");
|
||||
header('Access-Control-Allow-Credentials: true');
|
||||
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
|
||||
|
||||
Reference in New Issue
Block a user