Skip to content

[Security] Missing State Validation in /consoleapi/system/initialize Allows Unauthenticated Root Account Creation (Privilege Escalation) #135

Description

@Captaince

Description

During a security audit and code review, a critical logic flaw was discovered in the BuildingAI system's initialization endpoint (/consoleapi/system/initialize).

The endpoint is exposed with the @Public() decorator, allowing unauthenticated access. However, the underlying business logic fails to verify whether the system has already been initialized. This allows an unauthenticated external attacker to bypass authentication on a fully deployed system, forcefully create a new Root administrator account, and completely take over the application.

Affected Components

  • Controller: packages/api/src/modules/system/controllers/console/system.controller.ts (Lines 38-47)
  • Service: SystemService.initialize() (system.service.ts around Line 72)
  • Endpoint: POST /consoleapi/system/initialize

Root Cause Analysis

In system.controller.ts, the endpoint is exposed publicly:

@Public()
@Post("initialize")
async setSystemInfo(@Body() dto: initializeDto, ...) {
    return this.systemService.initialize(dto, ipAddress, userAgent);
}

In the SystemService.initialize method, the code only checks if the provided username already exists in the database. It completely lacks a global state check (e.g., checking an isInitialized flag) to determine if the setup process has already been completed.

If an attacker provides a new, unique username, the system provisions the account with isRoot: BooleanNumber.YES and immediately returns a valid JWT token:

// Missing check: if (globalConfig.isInitialized) { throw Error(...) } 
const user = await this.userService.create({
    username: dto.username,
    password: hashedPassword,
    isRoot: BooleanNumber.YES, // Core escalation trigger
    ...
});
// Returns valid JWT for the new root user

Steps to Reproduce (PoC)

  1. Identify a running, already-initialized instance of the BuildingAI system.
  2. Send the following HTTP POST request without any authentication headers/tokens:
POST /consoleapi/system/initialize HTTP/1.1
Host: [Target-IP]
Content-Type: application/json

{
    "username": "attacker_root_1",
    "password": "AttackerPass123!",
    "confirmPassword": "AttackerPass123!"
}
  1. Observe the HTTP 200 OK response containing a newly generated JWT token for the attacker_root_1 user.
  2. Use the returned JWT token to access administrative API endpoints.

Security Impact

  • Severity: Critical (Expected CVSS v3.1 Score: 9.8)
  • Consequences: Complete system compromise. An unauthenticated remote attacker can indefinitely provision highest-privilege accounts, leading to unauthorized data access, data exfiltration, system manipulation, and severe business disruption.

Suggested Remediation

It is highly recommended to introduce a global state flag (e.g., isInitialized in a system settings table or configuration file).

Update the SystemService.initialize method to validate this flag at the very beginning of the function:

async initialize(dto: initializeDto, ...) {
    // 1. Check if the system has already been initialized
    const systemSettings = await this.settingService.getSystemSettings();
    if (systemSettings.isInitialized) {
        throw HttpErrorFactory.forbidden("System has already been initialized. Root user creation is locked.");
    }
    
    // 2. Existing username uniqueness check
    const existingUser = await this.userService.findOne({
        where: { username: dto.username },
    });
    if (existingUser) {
        throw HttpErrorFactory.badRequest("User already exists");
    }
    
    // ... remaining user creation logic ...

    // 3. After successful root creation, ensure systemSettings.isInitialized is set to true and saved to the database.
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions