VYPR
Critical severityNVD Advisory· Published Nov 6, 2024· Updated Nov 6, 2024

CVE-2024-10082

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.

PackageAffected versionsPatched versions
codecheckerPyPI
< 6.24.26.24.2

Affected products

1

Patches

1
866f3796d01f

Removing the root user creation

https://github.com/Ericsson/codecheckerDaniel KruppOct 15, 2024via ghsa
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>
     
     ![Global permission manager](images/permissions.png)
    @@ -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

News mentions

0

No linked articles in our index yet.