CVE-2024-10082
Description
CodeChecker is an analyzer tooling, defect database and viewer extension for the Clang Static Analyzer and Clang Tidy. Authentication method confusion allows logging in as the built-in root user from an external service. The built-in root user up until 6.24.1 is generated in a weak manner, cannot be disabled, and has universal access.This vulnerability allows an attacker who can create an account on an enabled external authentication service, to log in as the root user, and access and control everything that can be controlled via the web interface. The attacker needs to acquire the username of the root user to be successful.
This issue affects CodeChecker: through 6.24.1.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
codecheckerPyPI | < 6.24.2 | 6.24.2 |
Affected products
1- Range: 0
Patches
1866f3796d01fRemoving the root user creation
7 files changed · +73 −189
docs/web/permissions.md+28 −33 modified@@ -18,45 +18,40 @@ on the product level. Table of Contents ================= -* [The master superuser (root)](#the-master-superuser) -* [Managing permissions](#managing-permissions) -* [Permission concepts](#permission-concepts) - * [Default value](#default-value) - * [Permission inheritance](#permission-inheritance) - * [Permission manager](#permission-manager) -* [Available permissions](#available-permissions) - * [Server-wide (global) permissions](#global-permissions) - * [`SUPERUSER`](#superuser) - * [`PERMISSION_VIEW`](#permission-view) - * [Product-level permissions](#product-level-permissions) - * [`PRODUCT_ADMIN`](#product-admin) - * [`PRODUCT_ACCESS`](#product-access) - * [`PRODUCT_STORE`](#product-store) - * [`PRODUCT_VIEW`](#product-view) +- [Permission subsystem](#permission-subsystem) +- [Table of Contents](#table-of-contents) +- [The master superuser (root) ](#the-master-superuser-root-) +- [Managing permissions ](#managing-permissions-) +- [Permission concepts ](#permission-concepts-) + - [Default value ](#default-value-) + - [Permission inheritance ](#permission-inheritance-) + - [Permission manager ](#permission-manager-) +- [Available permissions ](#available-permissions-) + - [Server-wide (global) permissions ](#server-wide-global-permissions-) + - [`SUPERUSER` ](#superuser-) + - [`PERMISSION_VIEW`](#permission_view) + - [Product-level permissions ](#product-level-permissions-) + - [`PRODUCT_ADMIN` ](#product_admin-) + - [`PRODUCT_ACCESS` ](#product_access-) + - [`PRODUCT_STORE` ](#product_store-) + - [`PRODUCT_VIEW` ](#product_view-) # The master superuser (root) <a name="the-master-superuser"></a> -Each CodeChecker server at its first start generates a master superuser -(*root*) access credential which it prints into its standard output: +At the first CodeChecker startup it is recommended that +you set up a single user with `SUPERUSER` permission. +Then with this user you will be able to configure additional permissions +for other users in the WEB GUI. +Let's say you want to give `SUPERUSER` permission to user `admin`. +Then set `super_user` field in the `server_config.json` configuration file: ```sh -[WARNING] Server started without 'root.user' present in CONFIG_DIRECTORY! -A NEW superuser credential was generated for the server. This information IS -SAVED, thus subsequent server starts WILL use these credentials. You WILL NOT -get to see the credentials again, so MAKE SURE YOU REMEMBER THIS LOGIN! ------------------------------------------------------------------ -The superuser's username is 'AAAAAA' with the password 'aaaa0000' ------------------------------------------------------------------ +"authentication": { + "enabled" : true, + "super_user" : "admin", +... ``` -These credentials can be deleted and new ones can be requested by starting -CodeChecker server with the `--reset-root` flag. The credentials are always -**randomly generated**. - -If the server has authentication enabled, the *root* user will **always have -access** despite of the configured authentication backends' decision, and -will automatically **have the `SUPERUSER` permission**. - # Managing permissions <a name="managing-permissions"></a>  @@ -184,4 +179,4 @@ delete existing analysis runs from the server. |---------|-----------------|-----------------| | Granted | `PRODUCT_ADMIN` | `PRODUCT_ADMIN`, `PRODUCT_STORE`, `PRODUCT_ACCESS` | -Users need the `PRODUCT_VIEW` permission to `view` analysis runs without modifying any properties of the runs. \ No newline at end of file +Users need the `PRODUCT_VIEW` permission to `view` analysis runs without modifying any properties of the runs. \ No newline at end of file
docs/web/user_guide.md+18 −23 modified@@ -12,8 +12,8 @@ - [Configuring database and server settings location](#configuring-database-and-server-settings-location) - [Server Configuration (Authentication and Server Limits)](#server-configuration-authentication-and-server-limits) - [Database Configuration](#database-configuration) - - [Master superuser and authentication forcing](#master-superuser-and-authentication-forcing) - - [Enfore secure socket (TLS/SSL)](#enfore-secure-socket-ssl) + - [Initial super-user](#initial-super-user) + - [Enfore secure socket (TLS/SSL)](#enfore-secure-socket-tlsssl) - [Managing running servers](#managing-running-servers) - [Manage server database upgrades](#manage-server-database-upgrades) - [`store`](#store) @@ -150,7 +150,7 @@ usage: CodeChecker server [-h] [-w WORKSPACE] [-f CONFIG_DIRECTORY] [--sqlite SQLITE_FILE | --postgresql] [--dbaddress DBADDRESS] [--dbport DBPORT] [--dbusername DBUSERNAME] [--dbname DBNAME] - [--reset-root] [--force-authentication] + [--force-authentication] [-l | -r | -s | --stop-all] [--db-status STATUS | --db-upgrade-schema PRODUCT_TO_UPGRADE | --db-force-upgrade] [--verbose {info,debug,debug_analyzer}] @@ -309,26 +309,21 @@ project. **It is recommended to use only the Postgresql databse for production deployments!** -#### Master superuser and authentication forcing - -``` -root account arguments: - Servers automatically create a root user to access the server's - configuration via the clients. This user is created at first start and - saved in the CONFIG_DIRECTORY, and the credentials are printed to the - server's standard output. The plaintext credentials are NEVER accessible - again. - - --reset-root Force the server to recreate the master superuser - (root) account name and password. The previous - credentials will be invalidated, and the new ones will - be printed to the standard output. - --force-authentication - Force the server to run in authentication requiring - mode, despite the configuration value in - 'session_config.json'. This is needed if you need to - edit the product configuration of a server that would - not require authentication otherwise. +#### Initial super-user + +You can give a single user SUPER_USER permission +by setting the `super_user` field in the `authentication` +section of the `server_config.json`. +The user which is set here, must be an existing user. +For example it should be a user +with dictionary authentication method. + +``` + "authentication": { + "enabled" : true, + "super_user" : "admin", +... + ``` #### Enfore secure socket (TLS/SSL)
web/server/codechecker_server/cmd/server.py+0 −20 modified@@ -212,17 +212,6 @@ def add_arguments_to_parser(parser): CONFIG_DIRECTORY, and the credentials are printed to the server's standard output. The plaintext credentials are NEVER accessible again.""") - root_account.add_argument('--reset-root', - dest="reset_root", - action='store_true', - default=argparse.SUPPRESS, - required=False, - help="Force the server to recreate the master " - "superuser (root) account name and " - "password. The previous credentials will " - "be invalidated, and the new ones will be " - "printed to the standard output.") - root_account.add_argument('--force-authentication', dest="force_auth", action='store_true', @@ -932,15 +921,6 @@ def server_init_start(args): not os.path.isdir(os.path.dirname(args.sqlite)): os.makedirs(os.path.dirname(args.sqlite)) - if 'reset_root' in args: - try: - os.remove(os.path.join(args.config_directory, 'root.user')) - LOG.info("Master superuser (root) credentials invalidated and " - "deleted. New ones will be generated...") - except OSError: - # File doesn't exist. - pass - if 'force_auth' in args: LOG.info("'--force-authentication' was passed as a command-line " "option. The server will ask for users to authenticate!")
web/server/codechecker_server/server.py+11 −59 modified@@ -14,17 +14,14 @@ import atexit import datetime from functools import partial -from hashlib import sha256 from http.server import HTTPServer, SimpleHTTPRequestHandler import os import posixpath -from random import sample import shutil import signal import socket import ssl import sys -import stat from typing import List, Optional, Tuple import urllib @@ -68,8 +65,6 @@ Configuration as ORMConfiguration from .database.database import DBSession from .database.run_db_model import IDENTIFIER as RUN_META, Run, RunLock -from .tmp import get_tmp_dir_hash - LOG = get_logger('server') @@ -991,43 +986,6 @@ class CCSimpleHttpServerIPv6(CCSimpleHttpServer): address_family = socket.AF_INET6 -def __make_root_file(root_file): - """ - Generate a root username and password SHA. This hash is saved to the - given file path, and is also returned. - """ - - LOG.debug("Generating initial superuser (root) credentials...") - - username = ''.join(sample("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 6)) - password = get_tmp_dir_hash()[:8] - - LOG.info("A NEW superuser credential was generated for the server. " - "This information IS SAVED, thus subsequent server starts " - "WILL use these credentials. You WILL NOT get to see " - "the credentials again, so MAKE SURE YOU REMEMBER THIS " - "LOGIN!") - - # Highlight the message a bit more, as the server owner configuring the - # server must know this root access initially. - credential_msg = f"The superuser's username is '{username}' with the " \ - f"password '{password}'" - LOG.info("-" * len(credential_msg)) - LOG.info(credential_msg) - LOG.info("-" * len(credential_msg)) - - sha = sha256((username + ':' + password).encode('utf-8')).hexdigest() - secret = f"{username}:{sha}" - with open(root_file, 'w', encoding="utf-8", errors="ignore") as f: - LOG.debug("Save root SHA256 '%s'", secret) - f.write(secret) - - # This file should be only readable by the process owner, and noone else. - os.chmod(root_file, stat.S_IRUSR) - - return secret - - def start_server(config_directory, package_data, port, config_sql_server, listen_address, force_auth, skip_db_cleanup: bool, context, check_env): @@ -1038,22 +996,17 @@ def start_server(config_directory, package_data, port, config_sql_server, server_addr = (listen_address, port) + # The root user file is DEPRECATED AND IGNORED root_file = os.path.join(config_directory, 'root.user') - if not os.path.exists(root_file): - LOG.warning("Server started without 'root.user' present in " - "CONFIG_DIRECTORY!") - root_sha = __make_root_file(root_file) - else: - LOG.debug("Root file was found. Loading...") - try: - with open(root_file, 'r', encoding="utf-8", errors="ignore") as f: - root_sha = f.read() - LOG.debug("Root digest is '%s'", root_sha) - except IOError: - LOG.info("Cannot open root file '%s' even though it exists", - root_file) - root_sha = __make_root_file(root_file) - + if os.path.exists(root_file): + LOG.warning("The 'root.user' file: %s" + " is deprecated and ignored. If you want to" + " setup an initial user with SUPER_USER permission," + " configure the super_user field in the server_config.json" + " as described in the documentation." + " To get rid off this warning," + " simply delete the root.user file.", + root_file) # Check whether configuration file exists, create an example if not. server_cfg_file = os.path.join(config_directory, 'server_config.json') if not os.path.exists(server_cfg_file): @@ -1077,7 +1030,6 @@ def start_server(config_directory, package_data, port, config_sql_server, try: manager = session_manager.SessionManager( server_cfg_file, - root_sha, force_auth) except IOError as ioerr: LOG.debug(ioerr) @@ -1098,7 +1050,7 @@ def start_server(config_directory, package_data, port, config_sql_server, "Earlier logs might contain additional detailed " "reasoning.\n\t* %s", len(fails), "\n\t* ".join( - (f"'{ep}' ({reason})" for (ep, reason) in fails) + (f"'{ep}' ({reason})" for (ep, reason) in fails) )) else: LOG.debug("Skipping db_cleanup, as requested.")
web/server/codechecker_server/session_manager.py+10 −33 modified@@ -9,7 +9,6 @@ Handles the management of authentication sessions on the server's side. """ -import hashlib import json import os import re @@ -161,13 +160,12 @@ class SessionManager: CodeChecker server. """ - def __init__(self, configuration_file, root_sha, force_auth=False): + def __init__(self, configuration_file, force_auth=False): """ Initialise a new Session Manager on the server. :param configuration_file: The configuration file to read authentication backends from. - :param root_sha: The SHA-256 hash of the root user's authentication. :param force_auth: If True, the manager will be enabled even if the configuration file disables authentication. """ @@ -199,9 +197,6 @@ def __init__(self, configuration_file, root_sha, force_auth=False): self.__refresh_time = self.__auth_config['refresh_time'] \ if 'refresh_time' in self.__auth_config else None - # Save the root SHA into the configuration (but only in memory!) - self.__auth_config['method_root'] = root_sha - self.__regex_groups_enabled = False # Pre-compile the regular expressions of 'regex_groups' @@ -334,17 +329,16 @@ def get_realm(self): "error": self.__auth_config.get('realm_error') } + @property + def get_super_user(self): + return { + "super_user": self.__auth_config.get('super_user'), + } + @property def default_superuser_name(self) -> Optional[str]: """ Get default superuser name. """ - root = self.__auth_config['method_root'].split(":") - - # Previously the root file doesn't contain the user name. In this case - # we will return with no user name. - if len(root) <= 1: - return None - - return root[0] + return self.__auth_config['super_user'] def set_database_connection(self, connection): """ @@ -365,8 +359,7 @@ def __handle_validation(self, auth_string): This validation object contains two keys: username and groups. """ - validation = self.__try_auth_root(auth_string) \ - or self.__try_auth_dictionary(auth_string) \ + validation = self.__try_auth_dictionary(auth_string) \ or self.__try_auth_pam(auth_string) \ or self.__try_auth_ldap(auth_string) if not validation: @@ -387,22 +380,6 @@ def __is_method_enabled(self, method): 'method_' + method in self.__auth_config and \ self.__auth_config['method_' + method].get('enabled') - def __try_auth_root(self, auth_string): - """ - Try to authenticate the user against the root username:password's hash. - """ - user_name = SessionManager.get_user_name(auth_string) - sha = hashlib.sha256(auth_string.encode('utf8')).hexdigest() - - if f"{user_name}:{sha}" == self.__auth_config['method_root']: - return { - 'username': SessionManager.get_user_name(auth_string), - 'groups': [], - 'root': True - } - - return False - def __try_auth_token(self, auth_string): if not self.__database_connection: return None @@ -562,7 +539,7 @@ def get_db_auth_session_tokens(self, user_name): def __is_root_user(self, user_name): """ Return True if the given user has system permissions. """ - if self.__auth_config['method_root'].split(":")[0] == user_name: + if self.__auth_config['super_user'] == user_name: return True transaction = None
web/server/vue-cli/e2e/init.workspace.js+4 −11 modified@@ -7,20 +7,19 @@ const WORKSPACE_DIR = path.join(CC_DIR, "workspace"); const SERVER_CONFIG = { authentication: { enabled : true, + "super_user" : "root", session_lifetime : 60000, refresh_time : 60, logins_until_cleanup : 30, method_dictionary: { enabled : true, - auths : [ "cc:admin" ], + auths : [ "cc:admin", + "root:S3cr3t" ], groups : {} } } }; -const ROOT_USER = - "root:2691b13e4c5eadd0adad38983e611b2caa19caaa3476ccf31cbcadddf65c321c"; - // Create workspace directory if it does not exists. if (!fs.existsSync(WORKSPACE_DIR)) { fs.mkdirSync(WORKSPACE_DIR); @@ -29,10 +28,4 @@ if (!fs.existsSync(WORKSPACE_DIR)) { // Create server configuration file and enable authentication. const serverConfigFile = path.join(WORKSPACE_DIR, "server_config.json"); const data = JSON.stringify(SERVER_CONFIG, null, " "); -fs.writeFileSync(serverConfigFile, data); - -// Generate initial root credentials. -// - username: root -// - password: S3cr3t -const rootUserFile = path.join(WORKSPACE_DIR, "root.user"); -fs.writeFileSync(rootUserFile, ROOT_USER); +fs.writeFileSync(serverConfigFile, data); \ No newline at end of file
web/tests/libtest/env.py+2 −10 modified@@ -10,13 +10,11 @@ """ -from hashlib import sha256 import os import json import tempfile import shutil import socket -import stat import subprocess from codechecker_common.util import load_json @@ -350,11 +348,12 @@ def enable_auth(workspace): scfg_dict = load_json(server_cfg_file, {}) scfg_dict["authentication"]["enabled"] = True + scfg_dict["authentication"]["super_user"] = "root" scfg_dict["authentication"]["method_dictionary"]["enabled"] = True scfg_dict["authentication"]["method_dictionary"]["auths"] = \ ["cc:test", "john:doe", "admin:admin123", "colon:my:password", "admin_group_user:admin123", "regex_admin:blah", - "permission_view_user:pvu"] + "permission_view_user:pvu", "root:root"] scfg_dict["authentication"]["method_dictionary"]["groups"] = \ {"admin_group_user": ["admin_GROUP"]} scfg_dict["authentication"]["regex_groups"]["enabled"] = True @@ -363,13 +362,6 @@ def enable_auth(workspace): encoding="utf-8", errors="ignore") as scfg: json.dump(scfg_dict, scfg, indent=2, sort_keys=True) - # Create a root user. - root_file = os.path.join(workspace, 'root.user') - with open(root_file, 'w', - encoding='utf-8', errors='ignore') as rootf: - rootf.write(f"root:{sha256(b'root:root').hexdigest()}") - os.chmod(root_file, stat.S_IRUSR | stat.S_IWUSR) - def enable_storage_of_analysis_statistics(workspace): """
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/Ericsson/codechecker/security/advisories/GHSA-fpm5-2wcj-vfr7ghsavendor-advisoryWEB
- github.com/advisories/GHSA-fpm5-2wcj-vfr7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-10082ghsaADVISORY
- github.com/Ericsson/codechecker/commit/866f3796d01f3158c49b87ccae3e09c0807c1c7bghsaWEB
- github.com/pypa/advisory-database/tree/main/vulns/codechecker/PYSEC-2024-183.yamlghsaWEB
News mentions
0No linked articles in our index yet.