Mostly safe — a couple of notes worth reading.
Scanned 5/3/2026, 7:11:27 PM·Cached result·Fast Scan·45 rules·How we decide ↗
AIVSS Score
Low
Severity Breakdown
0
critical
0
high
94
medium
115
low
MCP Server Information
Findings
This package scores 58/100 on safety with a B grade, driven primarily by 115 readiness issues and 59 instances of verbose error handling that could leak sensitive information. The 94 medium-severity findings include 16 server configuration gaps and 5 ANSI escape injection vulnerabilities that pose moderate security risks. While no critical or high-severity issues were detected, the readiness and information disclosure concerns warrant review before deployment in production environments.
No known CVEs found for this package or its dependencies.
Scan Details
Want deeper analysis?
Fast scan found 20 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.
20 of 20 findings
20 findings
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
| 134 | worktree_path = _resolve_worktree_path(cwd, name) |
| 135 | resolved = str(Path(worktree_path).resolve()) |
| 136 | else: |
| 137 | print("ERROR: need cwd+name or worktreePath in stdin payload", file=sys.stderr) |
| 138 | sys.exit(1) |
| 139 | |
| 140 | if event_type == "create": |
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.
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
| 613 | "", |
| 614 | "" |
| 615 | ], |
| 616 | "answer": "Flask implements `before_request` and `after_request` hooks through the use of decorators. \n\n- The `@app.before_request` decorator is used to register a function to run before each request. This function can be used to perform tasks such as authentication, logging, or setting up the environment for the request.\n\n- The `@app.after_request` decorator is used to register a function to run after each request. This function can be used to perform tasks suc |
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.
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
| 326 | """Post or update a PR comment via gh CLI.""" |
| 327 | if not PR_NUMBER or not GITHUB_TOKEN: |
| 328 | print("::warning::No PR_NUMBER or GITHUB_TOKEN — printing review to stdout") |
| 329 | print(body) |
| 330 | return |
| 331 | |
| 332 | # Check for existing speedreview comment to update |
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.
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
| 154 | print("[ab] §1.1 default-shape benchmark …", flush=True) |
| 155 | r11 = bench_11_default_shape(repo, storage) |
| 156 | |
| 157 | print("[ab] §1.1 narrow-query parity check …", flush=True) |
| 158 | r11_narrow = bench_11_narrow_parity(repo, storage) |
| 159 | |
| 160 | print("[ab] §1.2 budget-adherence benchmark …", flush=True) |
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.
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
| 531 | row["query"] = query |
| 532 | task_rows.append(row) |
| 533 | status = "ok" if "error" not in row else f"ERR:{row['error'][:60]}" |
| 534 | print(f" [{chunk_size}] '{query}' → {row.get('tokens', '?'):,} tokens ({status})", file=sys.stderr) |
| 535 | |
| 536 | results_by_chunk[chunk_size] = { |
| 537 | "chunk_size": chunk_size, |
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.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 154 | try: |
| 155 | owner, name = resolve_repo(repo, storage_path) |
| 156 | except ValueError as e: |
| 157 | return {"error": str(e)} |
| 158 | |
| 159 | # Load index ONCE for both modes |
| 160 | store = IndexStore(base_path=storage_path) |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 35 | return -2, "", "git command timed out" |
| 36 | except Exception as exc: |
| 37 | logger.debug("git subprocess error: %s", exc, exc_info=True) |
| 38 | return -3, "", str(exc) |
| 39 | |
| 40 | |
| 41 | def get_churn_rate( |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 616 | return {"status": "indexed", "folder": folder, "result": result} |
| 617 | except Exception as exc: |
| 618 | mark_reindex_failed(repo_id, str(exc)) |
| 619 | return {"status": "error", "folder": folder, "error": str(exc)} |
| 620 | |
| 621 | async def run(self) -> None: |
| 622 | """Main loop: monitor for crashed tasks and restart them. Self-restarts on crash.""" |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 118 | try: |
| 119 | owner, name = resolve_repo(repo, storage_path) |
| 120 | except ValueError as e: |
| 121 | return {"error": str(e)} |
| 122 | |
| 123 | store = IndexStore(base_path=storage_path) |
| 124 | index = store.load_index(owner, name) |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 245 | try: |
| 246 | owner, name = resolve_repo(repo, storage_path) |
| 247 | except ValueError as e: |
| 248 | return {"error": str(e)} |
| 249 | |
| 250 | store = IndexStore(base_path=storage_path) |
| 251 | index = store.load_index(owner, name) |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 34 | try: |
| 35 | owner, name = resolve_repo(repo, storage_path) |
| 36 | except ValueError as e: |
| 37 | return {"error": str(e)} |
| 38 | |
| 39 | store = IndexStore(base_path=storage_path) |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 940 | try: |
| 941 | owner, name = _resolve(repo, storage_path) |
| 942 | except ValueError as e: |
| 943 | return {"error": str(e)} |
| 944 | |
| 945 | store = IndexStore(base_path=storage_path) |
| 946 | index = store.load_index(owner, name) |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 253 | try: |
| 254 | owner, name = resolve_repo(repo, storage_path) |
| 255 | except ValueError as e: |
| 256 | return {"error": str(e)} |
| 257 | |
| 258 | store = IndexStore(base_path=storage_path) |
| 259 | index = store.load_index(owner, name) |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 137 | try: |
| 138 | owner, name = resolve_repo(repo, storage_path) |
| 139 | except ValueError as e: |
| 140 | return {"error": str(e)} |
| 141 | |
| 142 | store = IndexStore(base_path=storage_path) |
| 143 | index = store.load_index(owner, name) |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
Full exception detail or stack trace returned to the caller. Leaking tracebacks exposes internal paths, library versions, and query structure — useful recon for attackers.
Evidence
| 36 | try: |
| 37 | owner, name = resolve_repo(repo, storage_path) |
| 38 | except ValueError as e: |
| 39 | return {"error": str(e)} |
| 40 | |
| 41 | store = IndexStore(base_path=storage_path) |
| 42 | index = store.load_index(owner, name) |
Remediation
Log the full exception server-side with a correlation ID; return only {"error_id": id, "message": "internal error"} to the caller. Never enable Flask debug mode in production.
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
| 4331 | read_stream, |
| 4332 | write_stream, |
| 4333 | server.create_initialization_options(), |
| 4334 | ) |
| 4335 | except asyncio.CancelledError: |
| 4336 | pass |
| 4337 | finally: |
| 4338 | _sessions.pop(new_id, None) |
| 4339 | _session_tasks.pop(new_id, None) |
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
| 182 | try: |
| 183 | landmarks = _build_landmark_section() |
| 184 | if landmarks: |
| 185 | snapshot_text += landmarks |
| 186 | except Exception: |
| 187 | pass # Landmark enrichment must not block compaction |
| 188 | |
| 189 | # Return snapshot as hook output for context injection. |
| 190 | # PreCompact has no hookSpecificOutput variant in Claude Code's schema, |
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
| 21 | if raw is not None: |
| 22 | try: |
| 23 | return max(0.0, float(raw)) |
| 24 | except ValueError: |
| 25 | pass |
| 26 | return DEFAULT_THRESHOLD |
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
| 222 | if self._process and self._process.poll() is None: |
| 223 | try: |
| 224 | self._send_request("shutdown", {}) |
| 225 | self._send_notification("exit", None) |
| 226 | except Exception: |
| 227 | pass |
| 228 | try: |
| 229 | self._process.terminate() |
| 230 | self._process.wait(timeout=5) |
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
| 259 | extra_spec = None |
| 260 | if effective_extra: |
| 261 | try: |
| 262 | extra_spec = pathspec.PathSpec.from_lines("gitignore", effective_extra) |
| 263 | except Exception: |
| 264 | pass |
| 265 | |
| 266 | skip_dirs_regex = _build_skip_dirs_regex() |
| 267 | for dirpath, dirnames, filenames in os.walk(str(root), followlinks=False): |
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.