Mostly safe โ a couple of notes worth reading.
Scanned 5/3/2026, 6:43:54 PMยทCached resultยทFast Scanยท45 rulesยทHow we decide โ
AIVSS Score
Low
Severity Breakdown
0
critical
0
high
22
medium
4
low
MCP Server Information
Findings
This package has a B grade with a safety score of 82/100 but carries moderate risk due to 22 medium-severity findings, primarily around resource exhaustion vulnerabilities (15 instances) and insecure container image configurations (5 instances). While no critical or high-severity issues were detected, the combination of resource exhaustion risks and container security gaps means you should review deployment constraints and image sources before installation. The AIVSS score of 3.2/10 indicates limited readiness for production use without additional hardening.
No known CVEs found for this package or its dependencies.
Scan Details
Want deeper analysis?
Fast scan found 26 findings using rule-based analysis. Upgrade for LLM consensus across 5 judges, AI-generated remediation, and cross-file taint analysis.
Building your own MCP server?
Same rules, same LLM judges, same grade. Private scans stay isolated to your account and never appear in the public registry. Required for code your team hasnโt shipped yet.
26 of 26 findings
26 findings
Container base image uses the floating :latest tag. This provides no reproducibility โ the image content can change under you, and there is no signature to verify.
Evidence
| 6 | # Usage: |
| 7 | # docker compose -f test-infrastructure/docker-compose.yml run --rm build-windows |
| 8 | # docker compose -f test-infrastructure/docker-compose.yml run --rm test-windows |
| 9 | |
| 10 | FROM mstorsjo/llvm-mingw:latest |
| 11 | |
| 12 | # Install Wine + binfmt support for transparent .exe execution |
| 13 | RUN dpkg --add-architecture i386 && \ |
Remediation
Pin the base image by digest (e.g. python@sha256:...) or at minimum an exact semver tag (e.g. python:3.12.4-slim-bookworm). Never use :latest in production Dockerfiles.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 86 | print(f"Server output was:\n{output!r}") |
| 87 | sys.exit(1) |
| 88 | if "tools" not in output: |
| 89 | print("FAIL: tools/list response body missing 'tools' key") |
| 90 | print(f"Server output was:\n{output!r}") |
| 91 | sys.exit(1) |
Remediation
Strip C0/C1 control codes before printing user-controlled values. Python: re.sub(r"[\x00-\x08\x0b-\x1f\x7f]", "", s). Prefer a structured logger (json/logfmt) over raw print to stdout.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 168 | setLoading(true); |
| 169 | try { |
| 170 | const q = path ? `?path=${encodeURIComponent(path)}` : ""; |
| 171 | const res = await fetch(`/api/browse${q}`); |
| 172 | const data = await res.json(); |
| 173 | if (data.error) throw new Error(data.error); |
| 174 | setCurrentPath(data.path ?? ""); |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 135 | # --- Download binary --- |
| 136 | |
| 137 | fetch() { |
| 138 | local url="$1" tool="$2" |
| 139 | if [ "$tool" = "curl" ]; then |
| 140 | curl -fsSL "$url" |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 87 | useEffect(() => { |
| 88 | const poll = setInterval(async () => { |
| 89 | try { |
| 90 | const res = await fetch("/api/logs?lines=200"); |
| 91 | const data = await res.json(); |
| 92 | setLines(data.lines ?? []); |
| 93 | } catch { /* ignore */ } |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 184 | if (!currentPath) return; |
| 185 | setSubmitting(true); setError(null); |
| 186 | try { |
| 187 | const res = await fetch("/api/index", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ root_path: currentPath }) }); |
| 188 | const data = await res.json(); |
| 189 | if (!res.ok) throw new Error(data.error ?? "Failed"); |
| 190 | onCreated(); onClose(); |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 14 | const [info, setInfo] = useState(""); |
| 15 | |
| 16 | useEffect(() => { |
| 17 | fetch(`/api/project-health?name=${encodeURIComponent(name)}`) |
| 18 | .then((r) => r.json()) |
| 19 | .then((d) => { |
| 20 | setStatus(d.status ?? "corrupt"); |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 138 | const fetchProcesses = useCallback(async () => { |
| 139 | try { |
| 140 | const res = await fetch("/api/processes"); |
| 141 | const data = await res.json(); |
| 142 | setProcesses(data.processes ?? []); |
| 143 | setSelfMetrics({ |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 93 | } catch { /* ignore */ } |
| 94 | }, 2000); |
| 95 | /* Initial fetch */ |
| 96 | fetch("/api/logs?lines=200").then(r => r.json()).then(d => setLines(d.lines ?? [])).catch(() => {}); |
| 97 | return () => clearInterval(poll); |
| 98 | }, []); |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 82 | } |
| 83 | |
| 84 | function fetchData(url) { |
| 85 | return fetch(url).then(r => r.json()); |
| 86 | } |
| 87 | |
| 88 | module.exports = { render, fetchData }; |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 14 | maxNodes = 50000, |
| 15 | ): Promise<GraphData> { |
| 16 | const params = new URLSearchParams({ project, max_nodes: String(maxNodes) }); |
| 17 | const res = await fetch(`/api/layout?${params}`); |
| 18 | |
| 19 | if (!res.ok) { |
| 20 | const body = await res.json().catch(() => ({ error: res.statusText })); |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 278 | useEffect(() => { |
| 279 | const poll = setInterval(async () => { |
| 280 | try { |
| 281 | const data = await (await fetch("/api/index-status")).json(); |
| 282 | setJobs(data); |
| 283 | if (data.length > 0 && data.every((j: { status: string }) => j.status !== "indexing")) onDone(); |
| 284 | } catch { /* */ } |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 320 | const deleteProject = useCallback(async (name: string) => { |
| 321 | if (!confirm(`Delete index for "${name}"?`)) return; |
| 322 | try { await fetch(`/api/project?name=${encodeURIComponent(name)}`, { method: "DELETE" }); refresh(); } catch { /* */ } |
| 323 | }, [refresh]); |
| 324 | |
| 325 | return ( |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 72 | const fetchAdr = useCallback(async () => { |
| 73 | try { |
| 74 | const res = await fetch(`/api/adr?project=${encodeURIComponent(project)}`); |
| 75 | const data = await res.json(); |
| 76 | setHasAdr(data.has_adr ?? false); |
| 77 | if (data.content) setContent(data.content); |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 173 | return nil |
| 174 | } |
| 175 | |
| 176 | // validateURLScheme rejects non-https URLs before any fetch (defense-in-depth). |
| 177 | func validateURLScheme(rawURL string) error { |
| 178 | if !strings.HasPrefix(rawURL, "https://") { |
| 179 | return fmt.Errorf("refusing non-https URL: %s", rawURL) |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 142 | const [data, setData] = useState(null); |
| 143 | const [loading, setLoading] = useState(true); |
| 144 | useEffect(() => { |
| 145 | fetch('/api/data/${i}/' + id) |
| 146 | .then(r => r.json()) |
| 147 | .then(d => { setData(d); setLoading(false); }); |
| 148 | }, [id]); |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 216 | os.execv(str(bin_path), args) # noqa: S606 โ list form, no shell |
| 217 | else: |
| 218 | import subprocess |
| 219 | result = subprocess.run(args) # noqa: S603 โ list form, no shell=True |
| 220 | sys.exit(result.returncode) |
Remediation
Pass timeout= on every call: - HTTP: `requests.get(url, timeout=5)`, `httpx.get(url, timeout=5.0)` - Node fetch: `AbortSignal.timeout(5000)` - Subprocess: `subprocess.run(["cmd"], timeout=30, check=True)` Pick a value short enough to fail fast and retry.
Package declares an install-time hook (npm postinstall/preinstall/prepare, setup.py cmdclass override, custom setuptools install class, or non-default pyproject build-backend). Anyone installing this package runs the hook. Confirm the hook is necessary and review its contents; prefer shipping a plain library without install-time execution.
Evidence
| 25 | "codebase-memory-mcp": "./bin.js" |
| 26 | }, |
| 27 | "scripts": { |
| 28 | "postinstall": "node install.js" |
| 29 | }, |
| 30 | "engines": { |
| 31 | "node": ">=18" |
Remediation
Prefer libraries that do not require install-time code execution: - Drop `postinstall`/`preinstall`/`prepare` scripts if the work can happen at runtime or build-time instead. - Ship pre-built native binaries rather than compiling via a custom `cmdclass` or `build_ext` override. - For Dockerfiles: replace `RUN curl โฆ | sh` with a pinned download + checksum verification + explicit `RUN` of a named script. - If the hook is unavoidable, document exactly what it does so downstream reviewers
Dockerfile never sets a non-root `USER` directive, so the CMD runs as root by default. Any RCE or library-level vulnerability exploited inside this container gets full privileges (MCP Top-10 R3). Add `USER <non-root>` before CMD / ENTRYPOINT in the final stage โ e.g. `USER 1000`, `USER nobody`, or `USER nonroot` on distroless.
Evidence
| 1 | # Mirrors the Alpine CI environment for portable (musl static) builds. |
| 2 | # - Alpine 3.21 with musl libc |
| 3 | # - GCC + static zlib for fully static binaries |
| 4 | # - Produces portable Linux binaries that run on any distro |
| 5 | # |
| 6 | # Build: docker build -f test-infrastructure/Dockerfile.alpine -t cbm-alpine test-infrastructure/ |
| 7 | # Run: docker run --rm -v $(pwd):/src cbm-alpine |
| 8 | |
| 9 | FROM alpine:3.21@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c |
| 10 | |
| 11 | RUN apk add --no-cache \ |
| 12 | build-base |
Remediation
Create and switch to a non-root user before the CMD / ENTRYPOINT: RUN adduser --system --uid 1000 app USER 1000 Or reuse the base image's shipped non-root account (e.g. `USER nobody`, `USER nonroot` on distroless). Multi-stage builds only need the USER directive in the final stage.
Dockerfile never sets a non-root `USER` directive, so the CMD runs as root by default. Any RCE or library-level vulnerability exploited inside this container gets full privileges (MCP Top-10 R3). Add `USER <non-root>` before CMD / ENTRYPOINT in the final stage โ e.g. `USER 1000`, `USER nobody`, or `USER nonroot` on distroless.
Evidence
| 1 | # Mirrors the Ubuntu CI environment exactly: |
| 2 | # - Ubuntu 24.04 (same as GitHub Actions ubuntu-latest / ubuntu-24.04-arm) |
| 3 | # - GCC (system default) with ASan + UBSan + LeakSanitizer |
| 4 | # - libsqlite3-dev + zlib1g-dev (same as CI "Install deps" step) |
| 5 | # |
| 6 | # Build: docker build -t cbm-test test-infrastructure/ |
| 7 | # Run: docker run --rm -v $(pwd):/src cbm-test |
| 8 | |
| 9 | FROM ubuntu:noble |
| 10 | |
| 11 | # Minimal: gcc + zlib only. sqlite3 is vendored (compiled from source with ASan). |
| 12 | RUN apt-get update && apt-get install -y |
Remediation
Create and switch to a non-root user before the CMD / ENTRYPOINT: RUN adduser --system --uid 1000 app USER 1000 Or reuse the base image's shipped non-root account (e.g. `USER nobody`, `USER nonroot` on distroless). Multi-stage builds only need the USER directive in the final stage.
Dockerfile never sets a non-root `USER` directive, so the CMD runs as root by default. Any RCE or library-level vulnerability exploited inside this container gets full privileges (MCP Top-10 R3). Add `USER <non-root>` before CMD / ENTRYPOINT in the final stage โ e.g. `USER 1000`, `USER nobody`, or `USER nonroot` on distroless.
Evidence
| 1 | # Lint environment โ mirrors CI lint job exactly: |
| 2 | # - clang-format-20 (from LLVM apt repo) |
| 3 | # - cppcheck 2.20.0 (built from source, same as CI) |
| 4 | # |
| 5 | # Build: docker build -t cbm-lint -f test-infrastructure/Dockerfile.lint test-infrastructure/ |
| 6 | # Run: docker run --rm -v $(pwd):/src cbm-lint |
| 7 | |
| 8 | FROM ubuntu:noble |
| 9 | |
| 10 | RUN apt-get update && apt-get install -y --no-install-recommends \ |
| 11 | gcc g++ make cmake \ |
| 12 | libsqlite3-dev zlib1g-dev \ |
| 13 | pkg-config wget gnupg git ca-certificates \ |
| 14 | && rm -rf |
Remediation
Create and switch to a non-root user before the CMD / ENTRYPOINT: RUN adduser --system --uid 1000 app USER 1000 Or reuse the base image's shipped non-root account (e.g. `USER nobody`, `USER nonroot` on distroless). Multi-stage builds only need the USER directive in the final stage.
Dockerfile never sets a non-root `USER` directive, so the CMD runs as root by default. Any RCE or library-level vulnerability exploited inside this container gets full privileges (MCP Top-10 R3). Add `USER <non-root>` before CMD / ENTRYPOINT in the final stage โ e.g. `USER 1000`, `USER nobody`, or `USER nonroot` on distroless.
Evidence
| 1 | # Cross-compile AND run Windows tests locally using llvm-mingw + Wine. |
| 2 | # |
| 3 | # llvm-mingw: LLVM/Clang-based MinGW toolchain |
| 4 | # Wine: runs the resulting .exe for actual test execution |
| 5 | # |
| 6 | # Usage: |
| 7 | # docker compose -f test-infrastructure/docker-compose.yml run --rm build-windows |
| 8 | # docker compose -f test-infrastructure/docker-compose.yml run --rm test-windows |
| 9 | |
| 10 | FROM mstorsjo/llvm-mingw:latest |
| 11 | |
| 12 | # Install Wine + binfmt support for transparent .exe execution |
| 13 | RUN dpkg --add-architecture i386 && \ |
| 14 | apt-g |
Remediation
Create and switch to a non-root user before the CMD / ENTRYPOINT: RUN adduser --system --uid 1000 app USER 1000 Or reuse the base image's shipped non-root account (e.g. `USER nobody`, `USER nonroot` on distroless). Multi-stage builds only need the USER directive in the final stage.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 72 | json_lines = [] |
| 73 | for ln in lines: |
| 74 | try: |
| 75 | json_lines.append(_json.loads(ln)) |
| 76 | except _json.JSONDecodeError: |
| 77 | pass |
| 78 | |
| 79 | ids = {obj.get("id") for obj in json_lines if "id" in obj} |
| 80 | if 1 not in ids: |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 101 | pass # Non-fatal: checksum unavailable |
| 102 | finally: |
| 103 | try: |
| 104 | os.unlink(tmp_path) |
| 105 | except Exception: |
| 106 | pass |
| 107 | |
| 108 | |
| 109 | def _version() -> str: |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 1536 | try { |
| 1537 | *this = other; |
| 1538 | } |
| 1539 | catch (const Error&) {} // NOLINT(bugprone-empty-catch) |
| 1540 | } |
| 1541 | |
| 1542 | ~Macro() { |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 96 | print("codebase-memory-mcp: checksum verified.", file=sys.stderr) |
| 97 | break |
| 98 | except SystemExit: |
| 99 | raise |
| 100 | except Exception: |
| 101 | pass # Non-fatal: checksum unavailable |
| 102 | finally: |
| 103 | try: |
| 104 | os.unlink(tmp_path) |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.