During a security audit conducted on 2026-07-09 , 7 critical security vulnerabilities were identified in SxDevOps (main branch). These vulnerabilities range from Remote Code Execution (RCE) to privilege escalation and hardcoded credentials. This Issue reports all findings to the project maintainer as per the project's SECURITY.md policy.
Affected Version: v1.1 (Latest)
Vulnerability Overview
V-01: MCP STDIO Command Injection (RCE)
CWE: CWE-78 (OS Command Injection) CVSS 3.1: AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (9.8 Critical) Affected File: backend/aiops/services.py , lines ~14159-14178 Authentication Required: Yes (low-privilege user with aiops.mcp.manage permission)
The MCP (Model Context Protocol) server management feature allows authenticated users to create MCP servers of type stdio . The endpoint_or_command field is passed directly to subprocess.Popen() via shlex.split() without any validation or sanitization. When the MCP session is initialized (via test_connection API), the injected command is executed on the backend server with the privileges of the Django application process.
Additionally, the auth_config.env field allows setting arbitrary environment variables (including dangerous ones like LD_PRELOAD , PATH , PYTHONPATH ), further expanding the attack surface.
Vulnerable Code Pattern
Remote Code Execution on the backend server with Django process privileges
In observed deployment, execution as Windows Administrator account
Full credential extraction (SSH passwords stored in plaintext, API keys)
Lateral movement to all managed hosts via stored SSH credentials
Whitelist executables : Restrict endpoint_or_command to pre-approved executable paths; reject values containing shell metacharacters
Filter dangerous environment variables : Block LD_PRELOAD , PATH , PYTHONPATH , DYLD_INSERT_LIBRARIES in auth_config.env
Sandbox MCP processes : Run MCP STDIO subprocesses in an isolated container with minimal privileges
V-02: SSH exec_command Unfiltered Command Injection (Host RCE)
CWE: CWE-78 (OS Command Injection) CVSS 3.1: AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H (9.8 Critical) Affected File: backend/ops/host_tasks.py , lines ~293, 589 Authentication Required: Yes (user with ops.task.execute permission)
The TASK_RUN_COMMAND task type passes payload.command directly to paramiko.SSHClient.exec_command() without any filtering or escaping. While the TASK_SERVICE_STATUS branch uses shlex.quote() for sanitization, the TASK_RUN_COMMAND branch has zero filtering. An attacker can chain arbitrary commands using ; , && , || to execute them on target hosts.
Vulnerable Code Pattern
RCE on all SSH-managed hosts with the SSH user's privileges
Lateral movement from the SxDevOps server to all managed infrastructure
Full data access on all managed hosts
Apply shlex.quote() to payload.command before exec_command() , consistent with the TASK_SERVICE_STATUS branch
Implement a command whitelist/blacklist to block dangerous patterns ( rm -rf , curl|bash , reverse shells)
Require secondary confirmation for high-risk commands
V-03: LLM-Generated Shell Commands Enter Task Drafts Without Validation
CWE: CWE-78 (OS Command Injection) CVSS 3.1: AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H (9.1 Critical) Affected File: backend/aiops/services.py , lines ~12280-12379, 12765-12827 Authentication Required: Yes (user with AIOps chat access) User Interaction: Required (user confirms task draft)
The generate_host_task tool accepts a command parameter that comes directly from the LLM's tool call output. This value is passed into build_task_draft() without any validation against DANGEROUS_COMMAND_PATTERNS — a list that already exists in the codebase (containing rm -rf , shutdown , reboot , etc.) but is only applied to MCP output sanitization, never to task draft creation.
This creates an attack vector through prompt injection: an attacker can craft a chat message that causes the LLM to generate malicious commands, which then appear as legitimate task drafts awaiting user confirmation.
Vulnerable Code Pattern
Execution of destructive commands : LLM hallucination or prompt injection can produce rm -rf / , reverse shells, etc.
Social engineering amplification : Task drafts from the AI assistant carry implicit trust
Automation risk : The auto-materialize code path (currently disabled but fully implemented) would eliminate human confirmation
Apply DANGEROUS_COMMAND_PATTERNS validation in build_task_draft() — reject or flag matching commands
Highlight the full command text in the task confirmation UI for user review
If auto-materialize is not planned, remove the code path entirely
V-04: UserSerializer Allows Writing is_superuser/is_staff (Privilege Escalation)
CWE: CWE-266 (Incorrect Privilege Assignment) CVSS 3.1: AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (8.8 Critical) Affected File: backend/rbac/serializers.py , lines ~122-164 Authentication Required: Yes (user with rbac.user.manage permission)
UserSerializer includes is_superuser , is_staff , and is_active in its Meta.fields , but read_only_fields only protects date_joined and last_login . The update() method iterates over all validated_data fields and applies them via setattr() , meaning any user with rbac.user.manage permission can set is_superuser=True on any account — including their own — bypassing the entire RBAC permission system.
Vulnerable Code Pattern
Complete RBAC bypass : The entire permission system is undermined
Persistence : Attacker can create backdoor superuser accounts
Full system control : Superusers can access all API endpoints, manage all hosts, execute arbitrary commands
Add is_superuser , is_staff , and is_active to read_only_fields
If these fields need modification, create a separate restricted API with audit logging and secondary admin confirmation
Implement field-level permission checks — only existing superusers should grant superuser status
V-05: Hardcoded Default Superadmin Password admin/Admin@123456
CWE: CWE-798 (Use of Hard-coded Credentials) CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (9.8 Critical) Affected Files: backend/rbac/services.py (lines ~11-12), frontend/src/views/Login.vue (lines ~95, 120-122) Authentication Required: None (credentials are publicly visible)
SxDevOps contains a hardcoded default superadmin password Admin@123456 in two locations:
Backend : rbac/services.py defines DEFAULT_ADMIN_PASSWORD = 'Admin@123456' and the ensure_default_superuser() function creates a superadmin account with this password on first startup.
Backend : rbac/services.py defines DEFAULT_ADMIN_PASSWORD = 'Admin@123456' and the ensure_default_superuser() function creates a superadmin account with this password on first startup.
Frontend : Login.vue displays the default credentials on the login page and pre-fills the login form with admin / Admin@123456 .
Frontend : Login.vue displays the default credentials on the login page and pre-fills the login form with admin / Admin@123456 .
While the README documents these as demo accounts, the default behavior creates the account without forcing a password change, meaning any unmodified deployment is fully accessible to anyone who visits the login page.
Vulnerable Code Pattern
Trivial initial access : Any visitor to the login page obtains superadmin credentials
Cascading RCE : Combined with V-01, enables server-level code execution without technical exploitation
No security boundary : The platform provides no protection if the default password is not changed
Remove the credential display and pre-fill from the frontend login page
Force password change on first login after initial setup
Refuse to start the production server if the default admin password has not been changed
Generate a random admin password during first startup and log it once
V-06: Django SECRET_KEY Hardcoded with django-insecure- Prefix
CWE: CWE-798 (Use of Hard-coded Credentials) CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N (9.1 Critical) Affected File: backend/sxdevops/settings.py , lines ~341-344 Authentication Required: None
SxDevOps hardcodes a Django SECRET_KEY fallback value in sxdevops/settings.py . The key uses the django-insecure- prefix, which Django itself flags as insecure, yet it is used as a fallback when the SECRET_KEY environment variable is not set (the default behavior).
Vulnerable Code Pattern
If the SECRET_KEY environment variable is not configured (the default), this known hardcoded value is used.
With a known SECRET_KEY , attackers can:
Forge signed Django session cookies — assume the identity of any user (including superadmin)
Bypass CSRF protection — generate valid CSRF tokens
Generate valid password reset tokens for any account
Sign arbitrary data that the application trusts
Remove the hardcoded fallback value; raise an exception if SECRET_KEY is not set via environment variable
Generate a cryptographically random SECRET_KEY during deployment
Store in a secret management service (e.g., HashiCorp Vault, AWS Secrets Manager)
Rotate the SECRET_KEY immediately if the current value has been exposed
V-07: DEBUG Mode Defaults to True
CWE: CWE-489 (Active Debug Code) CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N (9.1 Critical) Affected File: backend/sxdevops/settings.py , line ~347 Authentication Required: None
SxDevOps sets DEBUG = True as the default value when the DEBUG environment variable is not configured. If the deployment omits this configuration (common for Docker-based deployments), the application runs in debug mode in production.
Vulnerable Code Pattern
In Django, DEBUG = True causes:
Detailed error pages on 500 errors — exposes full stack traces, local variables, SQL queries, and all settings values (including SECRET_KEY and database credentials)
Static file serving through Django (bypassing secure CDN configurations)
Enhanced logging that may include sensitive data
This vulnerability amplifies V-06: the exposed SECRET_KEY on a debug error page enables session forgery attacks.
Change the default value to False : DEBUG = _bool_value(os.getenv("DEBUG"), False)
Add a startup check that refuses to run in production if DEBUG = True
Document the requirement to explicitly set DEBUG=False in deployment guides
Additional References
Detailed advisory writeups are available in the reporter's advisory repository.
Advisory Repository:
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
