codebase-memory-mcp interacts deeply with your filesystem. It reads source files across your entire codebase, writes to agent configuration files, and spawns background processes. This is inherent to what it does — not a bug.
If you are uncomfortable with these access patterns, please audit the source code before running. The full source is available in this repository. Release archives produced by the current release pipeline are verifiably built from this source and can be independently verified via SLSA Build Level 3 provenance, Sigstore signatures, and SHA-256 checksums (see Verification below). Each archive contains a native executable and its authenticated release-owned runtime assets.
We are humans and can make mistakes. We take security seriously — it is Priority #1 for this project — but we cannot guarantee perfection. By using this software you accept responsibility for evaluating whether it meets your own security requirements.
Indexing, graph queries, semantic search, and MCP tool handling run locally. The MCP server does not upload source code, repository paths, graph indexes, query contents, environment variables, usage metrics, or telemetry.
The MCP server has one best-effort external runtime check: after MCP
initialize, it starts a background update-check thread that requests release
metadata from
https://api.github.com/repos/DeusData/codebase-memory-mcp/releases/latest.
That request is used only to show an update notice when a newer release exists.
It sends no project data; only standard HTTPS metadata, such as the destination
host and the normal curl request headers, are visible to GitHub and the
network path.
The update check is non-blocking for MCP startup and tool calls. If the machine
is offline, DNS fails, GitHub is unreachable, or curl exits with an error, the
check is ignored. The request is also bounded with curl --max-time 5; a
process shutting down immediately while the check is still running may wait for
that bounded background thread to finish.
Explicit install, package-manager, and codebase-memory-mcp update flows are
separate user-initiated network operations that download release assets and
checksums from GitHub.
We actively invite security researchers to try to break this project.
If you find a vulnerability — anything from a logic bug to a remote code execution — we want to know. You will receive a fast response, public credit (if you want it), and the knowledge that you helped make a tool used by developers worldwide more secure.
What we consider in scope:
- Arbitrary code execution via MCP tool inputs or CLI arguments
- File reads or writes outside the indexed project root
- Shell injection through any code path
- Binary tampering or supply chain attacks
- Privilege escalation or sandbox escapes
Please report privately rather than as a public issue so we can fix before public disclosure. See below for how.
If you discover a security vulnerability, please report it privately so we can fix it before public disclosure:
- Do NOT open a public issue, PR, or social-media post for security vulnerabilities.
- Preferred: use GitHub's private vulnerability reporting (the repository's Security → Report a vulnerability button). This keeps everything in one place and starts a private advisory automatically.
- Alternative: email martin.vogel.tech@gmail.com.
- Include: description, reproduction steps, affected version, and potential impact.
- Include your GitHub handle and a contact email. We use these to credit you and to invite you (read-only) to privately verify the fix before its release — see step 4 of the handling process. Let us know if you would prefer to remain anonymous.
This is a solo, volunteer-maintained project, so security handling is best-effort. As good-faith targets — not guarantees — we aim to:
- acknowledge your report within 7 days (usually much sooner);
- give an initial assessment and severity within 14 days;
- develop, validate, and release a fix as quickly as the severity warrants — typically within 90 days, and expedited for high-severity issues.
If something will take longer, we will tell you and keep you updated.
We follow coordinated disclosure: fixes are developed privately, validated
across all supported platforms, released, and only then disclosed publicly via a
GitHub Security Advisory
with a CVE and credit to you. The full handling process — including how you
can verify the fix before release — is documented in
docs/SECURITY-DISCLOSURE.md.
We will not pursue or support legal action against researchers who act in good faith — accessing only their own test data, avoiding privacy violations and service disruption, and giving us reasonable time to fix before public disclosure. Research conducted under this policy is considered authorised.
This project implements multiple layers of security verification. Every release archive is signed and checksummed, and every extracted runtime object must pass its applicable checks before users can download it (draft → verify → publish flow).
- 8-layer security audit suite runs on every build:
- Layer 1: Static allow-list for dangerous calls (
system/popen/fork) + hardcoded URLs - Layer 2: Binary string audit (URLs, credentials, dangerous commands)
- Layer 3: Network egress monitoring via strace (Linux)
- Layer 4: Install output path + content validation
- Layer 5: Smoke test hardening (clean shutdown, residual processes, version integrity)
- Layer 6: Graph UI audit (external domains, CORS, server binding, eval/iframe)
- Layer 7: MCP robustness (23 adversarial JSON-RPC payloads)
- Layer 8: Vendored dependency integrity (SHA-256 checksums, dangerous call scan)
- Layer 1: Static allow-list for dangerous calls (
- All dangerous function calls require a reviewed entry in
scripts/security-allowlist.txt - Time-bomb pattern detection — scans for
time()/sleep()near dangerous calls (could indicate delayed activation) - MCP tool handler file read audit — tracks file read count in
mcp.cagainst an expected maximum (detects added file reads that could exfiltrate data through tool responses) - CodeQL SAST — static application security testing on every push (taint analysis, CWE detection, data flow tracking). Any open alert blocks the release.
- Fuzz testing — random/mutated inputs to MCP server and Cypher parser (60 seconds per build). Catches crashes, segfaults, and memory errors that structured tests miss.
- Native antivirus scanning on every platform (any detection fails the build):
- Windows: Windows Defender with ML heuristics — the same engine end users run
- Linux: ClamAV with daily signature updates
- macOS: ClamAV with daily signature updates
Releases are created as drafts (invisible to users) and only published after all verification passes:
- SLSA Build Level 3 provenance for release archives — cryptographic attestation generated inside the trusted GitHub Actions build workflow immediately after each release archive is produced
- Sigstore cosign signing — keyless digital signatures verifiable by anyone
- SBOM — Software Bill of Materials (SPDX) listing all vendored dependencies
- SHA-256 checksums — published with every release
- VirusTotal scanning — every distinct extracted member and unpacked UI asset is scanned; downloadable
.tar.gz/.zipcontainers are not submitted. Each completed analysis must contain at least 50 decisive engine results, zero malicious verdicts, and zero suspicious verdicts. Release notes retain archive SHA-256 provenance and link durable public association, exact-scan-set, per-object-result, and evidence-checksum assets. - OpenSSF Scorecard — repository security health score
Scope of the SLSA claim: this is a build provenance claim for release artifacts. It proves the attested archive was produced by the repository's trusted GitHub-hosted build workflow from repository source. It is not third-party certification, it is not retroactive to older releases, and it does not mean the source code is vulnerability-free or that maintainers cannot change source. Consumers should verify the signer workflow, not only repository ownership.
If any antivirus engine flags any scanned release object, the release stays as a draft and is not published until the issue is investigated and resolved. There is no exception path in this release gate.
- Shell injection prevention —
cbm_validate_shell_arg()rejects metacharacters before allpopen()/system()calls - SQLite authorizer — blocks
ATTACH/DETACHat engine level (prevents file creation via SQL injection) - CORS locked to localhost — graph UI only accessible from localhost origins
- Path containment —
realpath()check prevents reading files outside project root - Process-kill restriction — only server-spawned PIDs can be terminated
- Release-set verification — installers verify the downloaded archive's exact member set and SHA-256 before the candidate executable is activated
Users can independently verify any release archive and the runtime set it contains:
# SLSA Build Level 3 provenance for release archives
gh attestation verify <downloaded-file> \
--repo DeusData/codebase-memory-mcp \
--signer-workflow DeusData/codebase-memory-mcp/.github/workflows/_build.yml
# Sigstore cosign (keyless signature)
cosign verify-blob --bundle <file>.bundle <file>
# SHA-256 checksum
sha256sum -c checksums.txt
# VirusTotal (follow the durable per-object results link in the release notes)
# https://www.virustotal.com/Some release binaries are reported by one engine — Microsoft — as
Trojan:Script/Wacatac.B!ml. We believe this is a false positive, we do not hide
it, and this section exists so you can check that judgement yourself rather than
take our word for it.
The !ml suffix marks a machine-learning / heuristic classification, not a
signature match. The Script token is a generic bucket in that naming scheme and
says nothing about script content — GitHub's own gh CLI and Anthropic's Claude
installer have both carried Trojan:Script/Wacatac.H!ml on native binaries.
Typically 61 of ~62 engines on VirusTotal return clean for the same file.
We dissected a full release matrix built from one commit. The verdicts split across every axis at once:
| Binary | Link | Verdict |
|---|---|---|
| linux-amd64 | dynamic | flagged |
| linux-amd64-portable | static | clean |
| linux-arm64 | dynamic | clean |
| linux-arm64-portable | static | flagged |
| darwin-amd64 | — | flagged |
| darwin-arm64 | — | clean |
| windows amd64 / arm64 | — | clean |
The static/dynamic axis inverts between architectures, so no build or link
property explains it. The two macOS binaries have identical segment structure and
still split. Sibling artifacts from one build landed in different variant
buckets (.B vs .C).
We also tested and rejected the obvious structural hypothesis: entropy is low everywhere (embedded vectors 4.17, parse tables 3.46 bits/byte, against 7.5–8.0 for genuinely packed payloads), so the binary does not resemble a packed dropper.
We removed every embedded shell script from the binary and moved the UI bundle and the agent integration templates out into separate verified files. The detection count did not drop — it simply moved between artifacts. We reverted both changes rather than keep permanent complexity that bought nothing. We are documenting that here because a negative result is still evidence.
The same !ml family repeatedly hits large, unsigned, native open-source
binaries:
- llama.cpp #15874, #24487, #24558 — including one DLL of many in a single archive, with nothing found on reverse engineering
- GitHub CLI #13306
- Microsoft's own Go toolchain #1255
- Anthropic Claude Code #36796
- yt-dlp #7532, Godot #110612, PyInstaller #5854, Tauri #2486, OpenAI Codex #2228, rust-lang/rust #88297
A Microsoft engineer on the Go team put it plainly: "we're aware of Windows Security/Defender issues with Go apps… we can't exactly go fix something and solve all Go false positives."
Deliberately reshaping a binary to avoid a classifier is what malware does, and it measurably backfires — the same Microsoft engineer reports that obfuscation "increases scrutiny rather than avoiding it." We would rather be scannable and explain a false positive than be unreadable and score well.
Every release ships the material needed to check our artifacts independently.
Use the commands in Verification above: SLSA Build Level 3
provenance ties the archive to the workflow run that produced it, Sigstore cosign
verifies the signature, and checksums.txt pins the bytes. The release notes
carry a durable per-object VirusTotal link for every scanned file, including any
tolerated detection — we publish those results whether or not they are clean.
You can also rebuild from source and compare: scripts/build.sh --with-ui
produces the shipped composition.
A release may ship with at most one detection, and only when the engine is
Microsoft and the label ends in !ml. Two or more engines, any signature-based
label, any other vendor, or any "suspicious" verdict blocks the release. That
rule is enforced in scripts/ci/check-virustotal.sh and pinned by
tests/test_vt_gate_policy_contract.sh.
We would genuinely rather be wrong in public than confidently wrong. If you find anything that explains or contradicts the assessment above:
- Open an issue with the
av-analysislabel — include the artifact SHA-256, the engine and label, and what you found. - If it looks like an actual compromise rather than a classifier artifact, use the private process in Reporting a Vulnerability instead.
A concrete finding changes our position. Signing is on the roadmap and will help on Windows, but note that no code-signing scheme exists that AV engines honour for Linux ELF binaries, so it is not a complete answer either.
| Version | Supported |
|---|---|
Latest 0.9.x |
Yes — security fixes land in the newest release |
| < 0.9 | No — please upgrade to the latest release |
Only the latest release is supported. Security fixes are shipped in a new patched release rather than backported to older versions; upgrading to the newest version is the supported path to receive them.