Self-hosted SEO and AI-search visibility: rank tracking, keyword research, competitors, backlinks, audits, an opportunity engine and an MCP server. AGPL-3.0. Canonical repo and issues: gitlab.com/betterbrainlab/better-search-lab
Drift inferred · capture-to-capture
No drift recorded — single capability capture; advisories appear once its surface changes.
transport stdio counts 2 tools · 0 res
· 0 prompts
permission surface via code analysis
tools
-
keyword_overview
-
list_projects
prompt-surface
shipped agent-instruction files + hidden-content / dangerous-code findings —
quoted from the analyzed source
analyzed commit f719fec · analyzer v33 · 9h ago
skills & prompt files 1
- agent-rules Heshamus-better-search-lab-f719fec/CLAUDE.md
danger signals1
- suspicious endpoint 169.254.169.254 (cloud metadata) Heshamus-better-search-lab-f719fec/tests/lib/crawl/fetch-site.test.ts :81
return new Response(null, { status: 302, headers: { location: "http://169.254.169.254/" } });
evidence-backed
findings quoted directly from the published source artifact — not inferred
code files: 555
filesystem 14
- fs (weak) Heshamus-better-search-lab-f719fec/scripts/gen-config-docs.ts :4
import { readFileSync, writeFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/scripts/probe-keyword-overview.ts :7
import { readFileSync, writeFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/db/migrations-present.test.ts :2
import { readdirSync, readFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/api-route-segments.test.ts :2
import { readdirSync, readFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/community-files.test.ts :3
import { existsSync, readFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/compose.test.ts :2
import { readFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/config-docs.test.ts :2
import { readFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/daylight.test.ts :2
import { readFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/docs-links.test.ts :2
import { existsSync, readFileSync, readdirSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/install-script.test.ts :3
import { readFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/license.test.ts :2
import { readFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/mcp-distribution.test.ts :2
import { readFileSync } from "node:fs";
show 2 more
- fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/placeholders.test.ts :3
import { readFileSync } from "node:fs"; - fs (weak) Heshamus-better-search-lab-f719fec/tests/repo/release.test.ts :2
import { existsSync, readFileSync } from "node:fs";
shell / exec 4
- shell (weak) Heshamus-better-search-lab-f719fec/tests/repo/community-files.test.ts :2
import { execFileSync } from "node:child_process"; - shell (weak) Heshamus-better-search-lab-f719fec/tests/repo/daylight-sweep.test.ts :2
import { execSync } from "node:child_process"; - shell (weak) Heshamus-better-search-lab-f719fec/tests/repo/install-script.test.ts :2
import { execFileSync } from "node:child_process"; - shell (weak) Heshamus-better-search-lab-f719fec/tests/repo/placeholders.test.ts :2
import { execFileSync } from "node:child_process";
network 33
- net Heshamus-better-search-lab-f719fec/mcp/server.ts :67
const res = await fetch(url, { - net Heshamus-better-search-lab-f719fec/src/components/competitor-manager.tsx :46
const res = await fetch(`/api/projects/${projectId}/competitors`, { - net Heshamus-better-search-lab-f719fec/src/components/competitor-suggestions.tsx :35
const res = await fetch(`/api/projects/${projectId}/competitors/suggest`, { method: "POST" }); - net Heshamus-better-search-lab-f719fec/src/components/create-admin-form.tsx :35
const res = await fetch("/api/setup/admin", { - net Heshamus-better-search-lab-f719fec/src/components/delete-account-form.tsx :18
const res = await fetch("/api/account", { method: "DELETE" }); - net Heshamus-better-search-lab-f719fec/src/components/first-run-card.tsx :18
await fetch("/api/settings/updates", { - net Heshamus-better-search-lab-f719fec/src/components/gap-table.tsx :60
const res = await fetch("/api/keywords", { - net Heshamus-better-search-lab-f719fec/src/components/integrations-form.tsx :108
const res = await fetch("/api/settings/integrations", { method: "PUT", headers: { "content-type": "application/json" }, body: JSON.stringify({ values: payload }) }); - net Heshamus-better-search-lab-f719fec/src/components/keyword-manager.tsx :41
const res = await fetch(`/api/keywords/${id}/track`, { - net Heshamus-better-search-lab-f719fec/src/components/keyword-overview.tsx :49
const res = await fetch("/api/keyword-overview", { - net Heshamus-better-search-lab-f719fec/src/components/mcp-token-manager.tsx :53
const res = await fetch(`/api/mcp-tokens?id=${encodeURIComponent(token.id)}`, { method: "DELETE" }); - net Heshamus-better-search-lab-f719fec/src/components/opportunity-actions.tsx :54
const res = await fetch(`/api/opportunities/${id}/status`, {
show 21 more
- net Heshamus-better-search-lab-f719fec/src/components/organic-keywords-table.tsx :70
const res = await fetch("/api/keywords", { - net Heshamus-better-search-lab-f719fec/src/components/password-form.tsx :30
const res = await fetch("/api/account/password", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ currentPassword: current, newPassword: next }) }); - net Heshamus-better-search-lab-f719fec/src/components/profile-review.tsx :71
const res = await fetch("/api/keywords", { - net Heshamus-better-search-lab-f719fec/src/components/project-edit-form.tsx :71
const res = await fetch(`/api/projects/${project.id}`, { - net Heshamus-better-search-lab-f719fec/src/components/rankings-table.tsx :99
fetch(`/api/keywords/${keywordId}/history`) - net Heshamus-better-search-lab-f719fec/src/components/reddit-brief-editor.tsx :62
const res = await fetch(`/api/projects/${projectId}/reddit-config`, { - net Heshamus-better-search-lab-f719fec/src/components/reddit-conversations.tsx :58
// Direct fetch (not the useJob hook — this is a synchronous PATCH, not an - net Heshamus-better-search-lab-f719fec/src/components/research-explorer.tsx :102
const res = await fetch("/api/research", { - net Heshamus-better-search-lab-f719fec/src/components/running-updates-panel.tsx :61
await fetch("/api/settings/updates", { - net Heshamus-better-search-lab-f719fec/src/components/settings-form.tsx :74
const res = await fetch(`/api/projects/${projectId}/settings`, { - net Heshamus-better-search-lab-f719fec/src/components/setup/build-step.tsx :24
const res = await fetch(`/api/projects/${projectId}/${ROUTES[key]}`, { method: "POST" }); - net Heshamus-better-search-lab-f719fec/src/components/setup/competitors-step.tsx :19
const res = await fetch(`/api/projects/${projectId}/onboarding`, { method: "PATCH", headers: { "content-type": "application/json" }, body: JSON.stringify({ competitors: state }) }); - net Heshamus-better-search-lab-f719fec/src/components/setup/dataforseo-step.tsx :25
await fetch("/api/settings/integrations", { - net Heshamus-better-search-lab-f719fec/src/components/setup/done-step.tsx :13
try { await fetch("/api/setup/state", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ completed: true }) }); } - net Heshamus-better-search-lab-f719fec/src/components/setup/llm-step.tsx :33
const res = await fetch("/api/setup/state", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ llmStep }) }); - net Heshamus-better-search-lab-f719fec/src/components/setup/profile-step.tsx :14
const res = await fetch(`/api/projects/${projectId}/onboarding`, { method: "PATCH", headers: { "content-type": "application/json" }, body: JSON.stringify(body) }); - net Heshamus-better-search-lab-f719fec/src/components/setup/site-step.tsx :29
const res = await fetch("/api/projects", { - net Heshamus-better-search-lab-f719fec/src/components/site-switcher.tsx :55
fetch("/api/projects") - net Heshamus-better-search-lab-f719fec/src/components/update-banner.tsx :20
await fetch("/api/settings/updates", { - net Heshamus-better-search-lab-f719fec/src/components/use-job.ts :70
const res = await fetch( - net Heshamus-better-search-lab-f719fec/src/components/users-manager.tsx :49
const res = await fetch(`/api/users/${encodeURIComponent(user.id)}`, { method: "PATCH", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
secrets 6
- secrets Heshamus-better-search-lab-f719fec/mcp/server.ts :65
const token = process.env.BSL_TOKEN ?? ""; - secrets (weak) Heshamus-better-search-lab-f719fec/scripts/probe-competitors-domain.ts :14
const password = process.env.DATAFORSEO_PASSWORD; - secrets (weak) Heshamus-better-search-lab-f719fec/scripts/probe-user-data.ts :9
const password = process.env.DATAFORSEO_PASSWORD; - secrets (weak) Heshamus-better-search-lab-f719fec/tests/lib/lifecycle/check.test.ts :11
// Same secret tests/setup/vitest-setup.ts falls back to for process.env.AUTH_SECRET, - secrets (weak) Heshamus-better-search-lab-f719fec/tests/lib/lifecycle/state.test.ts :11
// Same secret tests/setup/vitest-setup.ts falls back to for process.env.AUTH_SECRET, - secrets (weak) Heshamus-better-search-lab-f719fec/tests/setup/vitest-setup.ts :4
process.env.AUTH_SECRET ??= "test_auth_secret_0123456789_abcdefghijklmnop";
tool registrations 2
- list_projects Heshamus-better-search-lab-f719fec/mcp/server.ts :292
- keyword_overview Heshamus-better-search-lab-f719fec/mcp/server.ts :320
install hooks 1
- prepublishOnly Heshamus-better-search-lab-f719fec/mcp/package.json :19
npm run build
declared dependencies 31
- @anthropic-ai/sdk@^0.124.0
- @fontsource-variable/hanken-grotesk@^5.3.0
- bcryptjs@^3.0.3
- drizzle-orm@^0.45.2
- geist@^1.7.2
- next@^15.5.22
- next-auth@5.0.0-beta.32
- node-cron@^4.6.0
- nodemailer@^10.0.0
- postgres@^3.4.9
- react@^19.2.8
- react-dom@^19.2.8
show 19 more
- tsx@^4.23.5
- typescript@^5.9.3
- zod@^4.4.3
- @electric-sql/pglite@^0.5.4
- @tailwindcss/postcss@^4.3.3
- @testing-library/jest-dom@^7.0.0
- @testing-library/react@^16.3.2
- @types/bcryptjs@^3.0.0
- @types/node@^26.1.2
- @types/nodemailer@^8.0.1
- @types/react@^19.2.18
- @types/react-dom@^19.2.4
- @vitejs/plugin-react@^6.0.5
- drizzle-kit@^0.31.10
- jsdom@^30.0.1
- postcss@^8.5.25
- tailwindcss@^4.3.3
- vite-tsconfig-paths@^6.1.1
- vitest@^4.1.10