Analyst: latentcollapse
Date: 2026-03-08
Scope: Light-Heart-Labs/DreamServer public repository, local clone only — no live infrastructure touched
Tools: gitleaks 8.x, bandit 1.9.4, semgrep (auto config), shellcheck, manual review
Method: Passive static analysis. Apache 2.0 license permits full code audit.
| Severity | Count |
|---|---|
| Critical | 1 |
| High | 3 |
| Medium | 5 |
| Low | 2 |
The Critical finding should be addressed immediately — format-valid credentials traced to the founder's home path have been sitting in a public repository since the voice agent framework was committed. All other findings are fixable in a normal development cycle.
File: resources/frameworks/voice-agent/core/hvac-token-server.py:19-20
Detected by: gitleaks (generic-api-key)
API_KEY = 'APIRUdt****'
API_SECRET = 'bTpgs0****'The file header reads Deploy to: /home/michael/hvac-token-server.py. The org contact on GitHub is michael@lightheartlabs.com. The credentials are format-valid:
API_KEYis 15 characters — matches LiveKit API key formatAPI_SECRETis 43 characters — matches LiveKit API secret format
These are not placeholder values. They appear to be real LiveKit credentials belonging to the founder, committed as part of a voice agent reference implementation.
Impact: Anyone with repo access can generate valid LiveKit JWT tokens, join or publish to any LiveKit room associated with this account, and potentially eavesdrop on or inject into live voice sessions.
Remediation:
- Rotate the LiveKit API key and secret immediately at console.livekit.io
- Remove the file from git history:
git filter-repo --path resources/frameworks/voice-agent/core/hvac-token-server.py --invert-paths - Replace with environment variable references:
API_KEY = os.environ['LIVEKIT_API_KEY']
File: dream-server/config/searxng/settings.yml:3
Detected by: gitleaks (generic-api-key)
secret_key: "9d0e105e00289d066f0532614b135e5df22eeb2b6e0228bd4c0a4426ae3f39f0"Every DreamServer installation ships with this identical static secret. SearXNG uses secret_key for HMAC-signing session cookies and CSRF tokens. A user who has read this repo can forge valid session tokens on any DreamServer install that hasn't manually changed this value.
Impact: Session forgery and CSRF bypass on all default installations.
Remediation: Generate a unique secret during install (the installer already generates other secrets via openssl rand) and inject it into settings.yml at install time rather than shipping a static value in the repo.
Files:
dream-server/installers/lib/detection.sh:32—eval "$env_out"(capability profile)dream-server/installers/lib/detection.sh:75—eval "$env_out"(backend contract)dream-server/installers/macos.sh:81—eval "$PREFLIGHT_ENV"dream-server/installers/phases/04-requirements.sh:38—eval "$PREFLIGHT_ENV"
The installer uses eval "$env_out" to source variables from build-capability-profile.sh → classify-hardware.sh. This pipeline ingests hardware metadata including GPU name (from nvidia-smi output). If a GPU name contains shell metacharacters — either from a malicious driver, a spoofed nvidia-smi binary earlier in $PATH, or a future code change that passes user input — the eval will execute arbitrary commands with the privileges of the user running the installer.
Impact: Privilege escalation / arbitrary code execution during install on any system where the hardware detection pipeline can be influenced.
Remediation: Replace eval with a parser that only accepts KEY=value lines matching a strict allowlist of expected variable names. Example:
while IFS='=' read -r key value; do
case "$key" in
CAP_PLATFORM_ID|CAP_GPU_VENDOR|CAP_RECOMMENDED_TIER|...)
printf -v "$key" '%s' "$value" ;;
esac
done <<< "$env_out"Files:
dream-server/config/openclaw/openclaw.json:47-55dream-server/config/openclaw/openclaw-strix-halo.json:47-55dream-server/extensions/services/openclaw/compose.yaml:16,23
Three dangerous flags are active simultaneously in the default config:
"gateway": {
"host": "0.0.0.0",
"controlUi": {
"allowInsecureAuth": true,
"dangerouslyDisableDeviceAuth": true,
"dangerouslyAllowHostHeaderOriginFallback": true
}
}Combined with the Docker port mapping (${OPENCLAW_PORT:-7860}:18789 — also binds to 0.0.0.0 by default) and the entrypoint flag --bind lan, this results in completely unauthenticated access to an agent framework with exec, read, write, and sub-agent spawning tools exposed to all network interfaces.
Note: --bind lan in the entrypoint overrides the host field in the JSON config — both must be fixed together.
Impact: Anyone on the local network (or internet, if port-forwarded) can run arbitrary commands on the host machine without any authentication.
Remediation (partially addressed in PR #67):
"host": "0.0.0.0"→"host": "127.0.0.1"in both JSON configs ✓--bind lan→--bind localhostin entrypoint ✓- Port binding →
127.0.0.1:${OPENCLAW_PORT:-7860}:18789✓ - Follow-up needed: remove or gate
dangerouslyDisableDeviceAuth: true
File: dream-server/extensions/services/token-spy/db.py:77
Detected by: bandit (B608), semgrep (sqlalchemy-execute-raw-query)
conn.execute(f"ALTER TABLE usage ADD COLUMN {col} {typedef}")col and typedef are currently sourced from a hardcoded list, so this is not directly exploitable today. However the pattern is dangerous — any future refactor that passes externally-derived column names or type definitions here lands directly in a raw SQL string without parameterization. SQLite's ALTER TABLE does not support parameterized column names, but the value should at minimum be validated against a strict allowlist before interpolation.
Remediation: Add an explicit allowlist check: assert col in ALLOWED_COLS before the execute, and assert typedef in ALLOWED_TYPES.
Files: extensions/services/dashboard/Dockerfile, extensions/services/token-spy/Dockerfile
Detected by: semgrep (missing-user-entrypoint, missing-user)
Neither Dockerfile contains a USER directive. Processes inside both containers run as root. The dashboard container is internet-facing (port 3001).
Impact: If either container is compromised via a vulnerability in nginx, the React app, or the token-spy proxy, the attacker has root inside the container with full access to mounted volumes.
Remediation:
RUN addgroup -S dream && adduser -S dream -G dream
USER dreamFile: extensions/services/dashboard/nginx.conf:22
Detected by: semgrep (possible-nginx-h2c-smuggling)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';This combination creates known HTTP/2 cleartext (H2C) smuggling conditions. An attacker on the local network could potentially craft requests that bypass nginx's auth header injection and reach the dashboard-api backend directly, circumventing the Authorization: Bearer token.
Remediation: Unless WebSocket upgrades are explicitly needed on the /api/ path, change Connection to a static value: proxy_set_header Connection "close";
File: extensions/services/dashboard/src/hooks/useVoiceAgent.js:12
Detected by: semgrep (detect-insecure-websocket)
const LIVEKIT_URL = import.meta.env.VITE_LIVEKIT_URL || `ws://${getHost()}:7880`The fallback LiveKit URL uses ws:// (unencrypted WebSocket). All voice audio is transmitted in cleartext when VITE_LIVEKIT_URL is not explicitly set.
Remediation: Default to wss:// and document that users need a valid TLS cert or self-signed cert accepted by the browser for local use.
File: dream-server/installers/phases/11-services.sh:32-33
Detected by: shellcheck (SC2168, severity: error)
local some_var=... # line 32 — outside any function
local other_var=... # line 33 — outside any functionlocal is only valid inside functions. On bash this silently becomes a global variable; on strict POSIX shells (dash, sh) this is a syntax error and the installer will abort at this phase.
Remediation: Remove local keyword or wrap the code block in a function.
Files: extensions/services/dashboard/public/agents.html:7-9, extensions/services/dashboard/templates/index.html:7-9
Detected by: semgrep (missing-integrity)
External scripts loaded from CDNs without integrity attributes. If the CDN is compromised or the resource URL is hijacked, malicious JavaScript executes in the dashboard context with full access to API tokens and service credentials.
Remediation: Add integrity="sha384-..." and crossorigin="anonymous" to all CDN <script> and <link> tags.
Method: Passive HTTP header inspection Tool: Python urllib
The landing page at dreamserver.ai is missing all standard security headers:
| Header | Status |
|---|---|
Strict-Transport-Security |
Missing |
Content-Security-Policy |
Missing |
X-Frame-Options |
Missing |
X-Content-Type-Options |
Missing |
Referrer-Policy |
Missing |
Permissions-Policy |
Missing |
Low severity for a static marketing page, but notable for a product whose core value proposition is security and privacy.
Remediation: Add headers via Hostinger's CDN configuration or a _headers file (Netlify/Vercel-style). Five-minute fix.
- No live infrastructure was accessed. All findings are from static analysis of the public repository.
- The LiveKit credential finding (C1) should be treated as a responsible disclosure. Recommend rotating before this report is shared publicly.
- All other findings are standard code quality / security hygiene items appropriate for a public bug report or PR.
Report generated using ArchMCP red-team container (BlackArch Linux) + gitleaks, bandit, semgrep, shellcheck.