- Location
- dashboard/server.js:36
- Finding
- Unauthenticated Dashboard Binds Without a Loopback Restriction and Exposes Evolution Data with Wildcard CORS<![CDATA[
## Vulnerability Details
**File Location**: `dashboard/server.js:36-108`
**Vulnerability Type**: Unauthenticated network data exposure
**Risk Level**: Medium
### Vulnerable Code
```js
function gatherData() {
const pkg = readJsonSafe(path.join(SKILL_ROOT, 'package.json')) || {};
// Memory files
const feedbackAll = readJsonlSafe(path.join(MEMORY_DIR, 'feedback.jsonl'));
const knowledge = readJsonSafe(path.join(MEMORY_DIR, 'knowledge.json')) || { lessons: [] };
const predictor = readJsonSafe(path.join(MEMORY_DIR, 'predictor.json'));
const clusters = readJsonSafe(path.join(MEMORY_DIR, 'cluster-registry.json')) || [];
const embeddingsCacheSize = fileSizeSafe(path.join(MEMORY_DIR, 'embeddings-cache.json'));
// GEP assets
const genesData = readJsonSafe(path.join(GEP_DIR, 'genes.json')) || { genes: [] };
const capsulesData = readJsonSafe(path.join(GEP_DIR, 'capsules.json')) || { capsules: [] };
const failedCapsulesData = readJsonSafe(path.join(GEP_DIR, 'failed_capsules.json')) || { failed_capsules: [] };
const eventsAll = readJsonlSafe(path.join(GEP_DIR, 'events.jsonl'));
const recentEvents = eventsAll.slice(-10);
// Env settings
const env = {
EVOLVE_STRATEGY: process.env.EVOLVE_STRATEGY || '(not set)',
OLLAMA_URL: process.env.OLLAMA_URL || '(not set)',
OLLAMA_EMBED_MODEL: process.env.OLLAMA_EMBED_MODEL || '(not set)',
};
return {
version: pkg.version || 'unknown',
name: pkg.name || 'lshml',
timestamp: new Date().toISOString(),
feedback: feedbackAll,
knowledge,
predictor,
clusters,
embeddingsCacheSize,
genes: genesData.genes || [],
capsules: capsulesData.capsules || [],
failedCapsules: failedCapsulesData.failed_capsules || [],
recentEvents,
totalEvents: eventsAll.length,
env,
};
}
```
```js
function startServer(port) {
const server = http.createServer((req, res) => {
if (req.method === 'GET' && req.url === '/api/data') {
res.writeHead(200,
...[truncated 2657 chars]
- Remediation
- <![CDATA[
## Remediation Suggestions
1. Bind explicitly to a loopback interface:
```js
server.listen(port, '127.0.0.1', callback);
```
2. Consider separately binding to `::1` only when required.
3. Remove wildcard CORS. Use no CORS header for a same-origin dashboard or enforce a strict allowlist.
4. Require an unpredictable per-launch authentication token.
5. Reject requests with unexpected `Host` and `Origin` headers to reduce DNS-rebinding attacks.
6. Return summarized metrics instead of complete feedback, knowledge, capsule, and event records.
7. Add security headers, including `Content-Security-Policy`, `X-Content-Type-Options`, and `Cache-Control: no-store`.
8. Require an explicit warning and authentication configuration before permitting a non-loopback bind.
]]>