Use with caution. Address findings before production.
Scanned 6/8/2026, 5:32:11 AMยทCached resultยทFast Scanยท48 rulesยทHow we decide โ
AIVSS Score
Medium
Severity Breakdown
0
critical
0
high
43
medium
53
low
MCP Server Information
Findings
This package receives a C grade with a safety score of 60/100, driven primarily by 53 readiness issues and 18 resource exhaustion vulnerabilities that could impact stability and performance. While no critical or high-severity flaws were found, the 43 medium-severity findingsโparticularly around server configuration, data exfiltration risks, and verbose error handlingโsuggest the package needs hardening before production use. Installation is feasible for testing but requires careful evaluation of the resource exhaustion and configuration concerns for any production deployment.
No known CVEs found for this package or its dependencies.
Scan Details
Want deeper analysis?
Fast scan found 96 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.
Showing 1โ30 of 96 findings
96 findings
Service binds to 0.0.0.0 โ all network interfaces. For MCP servers that only need to talk to a single parent process, bind to 127.0.0.1 (or a Unix domain socket) instead.
Evidence
| 91 | WorkingDirectory=/app |
| 92 | EnvironmentFile=/app/.env |
| 93 | ExecStart=/app/venv/bin/python3 -m uvicorn datanexus.main:app \ |
| 94 | --host 0.0.0.0 --port 8000 --workers 2 |
| 95 | Restart=always |
| 96 | RestartSec=5 |
| 97 | StandardOutput=journal |
Remediation
Bind to 127.0.0.1 for local-only access. If cross-host access is truly required, put the service behind an authenticated reverse proxy rather than exposing it on 0.0.0.0.
Service binds to 0.0.0.0 โ all network interfaces. For MCP servers that only need to talk to a single parent process, bind to 127.0.0.1 (or a Unix domain socket) instead.
Evidence
| 7 | # Start feedback dashboard in background (port 8101) |
| 8 | uvicorn feedback.dashboard.server:app \ |
| 9 | --host 0.0.0.0 \ |
| 10 | --port 8101 \ |
| 11 | --log-level info & |
| 12 | DASHBOARD_PID=$! |
Remediation
Bind to 127.0.0.1 for local-only access. If cross-host access is truly required, put the service behind an authenticated reverse proxy rather than exposing it on 0.0.0.0.
Service binds to 0.0.0.0 โ all network interfaces. For MCP servers that only need to talk to a single parent process, bind to 127.0.0.1 (or a Unix domain socket) instead.
Evidence
| 1343 | if __name__ == "__main__": |
| 1344 | import uvicorn |
| 1345 | logging.basicConfig(level=logging.INFO) |
| 1346 | uvicorn.run("feedback.dashboard.server:app", host="0.0.0.0", port=_PORT, reload=False) |
Remediation
Bind to 127.0.0.1 for local-only access. If cross-host access is truly required, put the service behind an authenticated reverse proxy rather than exposing it on 0.0.0.0.
Service binds to 0.0.0.0 โ all network interfaces. For MCP servers that only need to talk to a single parent process, bind to 127.0.0.1 (or a Unix domain socket) instead.
Evidence
| 114 | WorkingDirectory=/app |
| 115 | EnvironmentFile=/app/.env |
| 116 | ExecStart=/app/venv/bin/python3 -m uvicorn feedback.dashboard.server:app \ |
| 117 | --host 0.0.0.0 --port 8101 --workers 1 |
| 118 | Restart=always |
| 119 | RestartSec=5 |
| 120 | StandardOutput=journal |
Remediation
Bind to 127.0.0.1 for local-only access. If cross-host access is truly required, put the service behind an authenticated reverse proxy rather than exposing it on 0.0.0.0.
Service binds to 0.0.0.0 โ all network interfaces. For MCP servers that only need to talk to a single parent process, bind to 127.0.0.1 (or a Unix domain socket) instead.
Evidence
| 515 | ) |
| 516 | main.run( |
| 517 | transport="streamable-http", |
| 518 | host="0.0.0.0", # nosec B104 |
| 519 | port=8000, |
| 520 | middleware=[Middleware(_ClientIPMiddleware), Middleware(_ApiKeyMiddleware)], |
| 521 | stateless_http=True, |
Remediation
Bind to 127.0.0.1 for local-only access. If cross-host access is truly required, put the service behind an authenticated reverse proxy rather than exposing it on 0.0.0.0.
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
| 83 | # โโ Structured error response shape โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
| 84 | # Return this dict on ANY error. Never raise. Never return str(e). |
| 85 | # error_code must come from ErrorCode enum below. |
| 86 | # |
| 87 | # { |
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
| 180 | "error": str(exc), |
| 181 | "haiku_available": False, |
| 182 | })) |
| 183 | return {"error": str(exc), "haiku_available": False} |
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.
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
| 53 | schedule_seconds=_SCHEDULE, |
| 54 | ) |
| 55 | |
| 56 | async def fetch(self) -> bytes: |
| 57 | """Fetch and cache EPO OPS OAuth token; probe fallback sources.""" |
| 58 | client_id = os.environ.get("EPO_CLIENT_ID", "") |
| 59 | client_secret = os.environ.get("EPO_CLIENT_SECRET", "") |
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
| 153 | schedule_seconds=_SCHEDULE, |
| 154 | ) |
| 155 | |
| 156 | async def fetch(self) -> bytes: |
| 157 | """ |
| 158 | Fetch NPPES data for top specialities. Returns a summary JSON blob |
| 159 | for the base class to hash and store. Per-speciality cache entries |
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
| 64 | schedule_seconds=_SCHEDULE, |
| 65 | ) |
| 66 | |
| 67 | async def fetch(self) -> bytes: |
| 68 | """Pre-seed top keyword categories.""" |
| 69 | seeded = 0 |
| 70 | async with httpx.AsyncClient( |
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
| 59 | self.ttl_seconds = ttl_seconds |
| 60 | self.schedule_seconds = schedule_seconds |
| 61 | |
| 62 | async def fetch(self) -> bytes: |
| 63 | """ |
| 64 | Override in subclass. Must return raw upstream response bytes. |
| 65 | Raise any exception on failure โ run_forever will catch it. |
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
| 83 | schedule_seconds=604800, # weekly โ data updates monthly |
| 84 | ) |
| 85 | |
| 86 | async def fetch(self) -> bytes: |
| 87 | """Download all 4 regional CSVs and index every EIN into Redis.""" |
| 88 | |
| 89 | total_rows = 0 |
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
| 69 | schedule_seconds=_SCHEDULE, # 21600 โ rate limit awareness |
| 70 | ) |
| 71 | |
| 72 | async def fetch(self) -> bytes: |
| 73 | """Pre-seed top regulatory keyword categories.""" |
| 74 | api_key = os.environ.get("REGULATIONS_GOV_KEY", "") |
| 75 | if not api_key: |
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
| 4 | Downloads from the official CISA GitHub mirror (cisagov/kev-data) โ see KEV_URL constant. |
| 5 | and stores in Redis as: |
| 6 | datanexus:kev:catalog โ full catalog JSON (TTL 25h) |
| 7 | datanexus:kev:fetched_at โ ISO timestamp of last successful fetch (TTL 25h) |
| 8 | datanexus:kev:last_refresh_error โ error message if refresh fails (TTL 7d) |
| 9 | |
| 10 | Invoked two ways: |
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
| 6 | Endpoints: |
| 7 | GET /ops/dashboard โ full HTML dashboard |
| 8 | GET /ops/api/metrics โ JSON metrics snapshot (same data, for fetch()) |
| 9 | GET /ops/health โ {"ok": true} |
| 10 | |
| 11 | The dashboard auto-refreshes every 15 seconds via JavaScript fetch(). |
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
| 38 | class IngestBase: |
| 39 | """ |
| 40 | Base ingest worker. Subclasses override fetch() only. |
| 41 | |
| 42 | Args: |
| 43 | tool_id: Tool this worker feeds (e.g. 'T04') |
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
| 52 | schedule_seconds=_SCHEDULE, |
| 53 | ) |
| 54 | |
| 55 | async def fetch(self) -> bytes: |
| 56 | """Fetch IANA RDAP bootstrap and store in Redis.""" |
| 57 | async with httpx.AsyncClient( |
| 58 | timeout=_TIMEOUT, headers=_HEADERS, follow_redirects=True |
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
| 106 | schedule_seconds=3600, |
| 107 | ) |
| 108 | |
| 109 | async def fetch(self) -> bytes: |
| 110 | """Pre-seed all 50 packages. Returns last raw response bytes.""" |
| 111 | seeded = 0 |
| 112 | last_raw = b"" |
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
| 344 | schedule_seconds=86400, |
| 345 | ) |
| 346 | |
| 347 | async def fetch(self) -> bytes: |
| 348 | """Download bulk extract and index all main charities into Redis.""" |
| 349 | log.info(json.dumps({ |
| 350 | "ts": _iso_now(), "event": "uk_bulk_download_start", "tool": self.tool_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
| 119 | except Exception as _cb_exc: |
| 120 | log.warning("ingest_base.circuit_check error: %s", _cb_exc) |
| 121 | |
| 122 | raw: bytes = await self.fetch() |
| 123 | payload_hash = compute_payload_hash(raw) |
| 124 | |
| 125 | # โโ Phase 1 validation โ before caching โโโโโโโโโโโโโโโโโโโโโโ |
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
| 13 | def __init__(self): |
| 14 | super().__init__('T04', 'irs_bmf', 604800, 86400) |
| 15 | |
| 16 | async def fetch(self) -> bytes: |
| 17 | async with httpx.AsyncClient(timeout=30.0) as client: |
| 18 | resp = await client.get(IRS_BMF_URL) |
| 19 | resp.raise_for_status() |
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
| 65 | Raise any exception on failure โ run_forever will catch it. |
| 66 | """ |
| 67 | raise NotImplementedError( |
| 68 | f"{self.__class__.__name__}.fetch() must be overridden." |
| 69 | ) |
| 70 | |
| 71 | async def run_forever(self) -> None: |
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
| 9 | GET /ops/api/metrics โ JSON metrics snapshot (same data, for fetch()) |
| 10 | GET /ops/health โ {"ok": true} |
| 11 | |
| 12 | The dashboard auto-refreshes every 15 seconds via JavaScript fetch(). |
| 13 | """ |
| 14 | |
| 15 | import logging |
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
| 221 | schedule_seconds=604800, |
| 222 | ) |
| 223 | |
| 224 | async def fetch(self) -> bytes: |
| 225 | """Fetch 990 filing index and cache financial records per EIN.""" |
| 226 | indexed = 0 |
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
| 373 | async function refresh() { |
| 374 | document.getElementById('refresh-label').textContent = 'fetchingโฆ'; |
| 375 | try { |
| 376 | const res = await fetch('/ops/api/metrics'); |
| 377 | if (!res.ok) throw new Error('HTTP ' + res.status); |
| 378 | const d = await res.json(); |
| 379 | const t = d.totals || {}; |
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.
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 113 | def error_response( |
| 114 | error_code: str, |
| 115 | message: str, |
| 116 | query_hash: str = "", |
| 117 | retry_after: int = 0, |
| 118 | ingest_healthy: bool = False, |
| 119 | upstream: str = "", |
Remediation
Shape the schema to the tool's actual intent: - Zod: chain `.enum([...])`, `.regex(/.../)`, or `.max(n)`; prefer `z.enum([...])` or `z.literal(...)` when the value set is small. - Pydantic: use `Literal["a", "b"]` or `Field(max_length=..., pattern=r"...")`. - JSON Schema: add `"enum"`, `"pattern"`, or `"maxLength"` to the property. An overbroad schema is an "overpowered tool" โ the model has nothing to prevent it from calling the tool with input far beyond what the tool's prose contract
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 223 | "name": "report_feedback", |
| 224 | "description": "Report an incorrect, incomplete or stale DataNexus tool result.", |
| 225 | "parameters": { |
| 226 | "query_hash": { "type": "string", "description": "16-char hex query hash from the tool response", "required": true }, |
| 227 | "issue": { "type": "string", "description": "Description of the issue", "required": true } |
| 228 | } |
| 229 | }, |
Remediation
Shape the schema to the tool's actual intent: - Zod: chain `.enum([...])`, `.regex(/.../)`, or `.max(n)`; prefer `z.enum([...])` or `z.literal(...)` when the value set is small. - Pydantic: use `Literal["a", "b"]` or `Field(max_length=..., pattern=r"...")`. - JSON Schema: add `"enum"`, `"pattern"`, or `"maxLength"` to the property. An overbroad schema is an "overpowered tool" โ the model has nothing to prevent it from calling the tool with input far beyond what the tool's prose contract
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 21 | "name": "search_datanexus_tools", |
| 22 | "description": "Search DataNexus tools by describing your task in plain English. Returns the most relevant tools for your query. Token-efficient.", |
| 23 | "parameters": { |
| 24 | "query": { "type": "string", "description": "Natural language description of your task", "required": true } |
| 25 | } |
| 26 | }, |
| 27 | { |
Remediation
Shape the schema to the tool's actual intent: - Zod: chain `.enum([...])`, `.regex(/.../)`, or `.max(n)`; prefer `z.enum([...])` or `z.literal(...)` when the value set is small. - Pydantic: use `Literal["a", "b"]` or `Field(max_length=..., pattern=r"...")`. - JSON Schema: add `"enum"`, `"pattern"`, or `"maxLength"` to the property. An overbroad schema is an "overpowered tool" โ the model has nothing to prevent it from calling the tool with input far beyond what the tool's prose contract
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 129 | # --- from FeedbackInput --- |
| 130 | tool_id: str |
| 131 | query_hash: str |
| 132 | signal: str |
| 133 | comment: str = "" |
| 134 | missing_fields: Optional[List[str]] = None |
Remediation
Shape the schema to the tool's actual intent: - Zod: chain `.enum([...])`, `.regex(/.../)`, or `.max(n)`; prefer `z.enum([...])` or `z.literal(...)` when the value set is small. - Pydantic: use `Literal["a", "b"]` or `Field(max_length=..., pattern=r"...")`. - JSON Schema: add `"enum"`, `"pattern"`, or `"maxLength"` to the property. An overbroad schema is an "overpowered tool" โ the model has nothing to prevent it from calling the tool with input far beyond what the tool's prose contract
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 49 | max_length=10, |
| 50 | description="Tool ID โ must be in FEEDBACK_ENABLED_TOOLS.", |
| 51 | ) |
| 52 | query_hash: str = Field( |
| 53 | min_length=16, |
| 54 | max_length=64, |
| 55 | description="Hash returned by the tool call โ links feedback to the audit record.", |
Remediation
Shape the schema to the tool's actual intent: - Zod: chain `.enum([...])`, `.regex(/.../)`, or `.max(n)`; prefer `z.enum([...])` or `z.literal(...)` when the value set is small. - Pydantic: use `Literal["a", "b"]` or `Field(max_length=..., pattern=r"...")`. - JSON Schema: add `"enum"`, `"pattern"`, or `"maxLength"` to the property. An overbroad schema is an "overpowered tool" โ the model has nothing to prevent it from calling the tool with input far beyond what the tool's prose contract
MCP tool file registers a tool, performs a destructive sink (fs.unlink / shutil.rmtree / DROP TABLE / DELETE FROM / TRUNCATE / UPDATE ... SET / HTTP DELETE|PUT|PATCH / subprocess / exec / spawn), and emits no audit event anywhere in the file. Without an audit event, an investigator cannot answer "who deleted record X on day Y?" โ the irreversible action leaves no trail. Closes the OWASP MCP Top 10:2025 MCP08 (Lack of Audit and Telemetry) gap. Distinct from MCP-201 (no confirmation) and MCP-283
Evidence
| 1 | """ |
| 2 | datanexus/tools/security_stateful.py โ Sprint 6 stateful security tools. |
| 3 | |
| 4 | Tools: |
| 5 | fetch_cve_watch โ persistent CVE watchlist (create/check/delete) |
| 6 | audit_sbom_continuous โ continuous SBOM monitoring (register/check/deregister) |
| 7 | |
| 8 | Redis key schema (dn: prefix): |
| 9 | dn:cve_watch:{watch_id} โ Hash (watch data) |
| 10 | dn:cve_watch_ids โ SET (watch index) |
| 11 | dn:sbom_watch:{watch_id} โ Hash (SBOM watch data) |
| 12 | dn:sbom_watch_ids โ SET (SBOM watch index) |
| 13 | |
| 14 | Scheduler: see datanex |
Remediation
Add a structured audit-event emit immediately after every destructive sink. Minimum schema: actor, action, target, outcome, request_id. Python: from acme.audit import audit_log @mcp.tool() def delete_record(token: str, record_id: str) -> dict: actor = verify_token(token) db.execute("DELETE FROM records WHERE id = %s", (record_id,)) audit_log( actor=actor.sub, action="delete_record", target=record_id, outcome=
MCP server holds a mutable shared container (cache / store / state / pool / registry / sessions / results / outputs) and mutates it via append / push / add / extend, but no caller-identity marker (user_id / session_id / caller_id / request_id / org_id / tenant_id / actor_id / subject / principal) appears anywhere in the file. A process-global list mutated from inside a tool handler with no caller partition leaks data across requests: a later caller can read what an earlier caller wrote. Closes
Evidence
| 1 | """ |
| 2 | datanexus/tools/t11.py โ T11 Global Patent Intelligence tool. |
| 3 | |
| 4 | Spec: DataNexus_MCP_Spec_v7_4.docx Section 4, T11 entry |
| 5 | |
| 6 | Exactly 4 data functions. Shared infrastructure tools (report_feedback, |
| 7 | report_mcpize_link) are registered ONCE in main.py โ NOT here. |
| 8 | |
| 9 | Data sources: |
| 10 | Primary: EPO OPS (Open Patent Services) โ ops.epo.org โ OAuth client_credentials |
| 11 | European Patent Office API; 4 GB/month free tier |
| 12 | Secondary: USPTO PatentsView โ api.patentsview.org โ no key required |
| 13 | |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server file uses Python's `global` keyword. `global` mutates module-level state from inside a function โ in a multi-tenant MCP server, this is almost always a cross-request data path. Closes the OWASP MCP Top 10:2025 MCP10 (Context Injection & Over-Sharing) gap. Fix: thread state through function arguments or a per-request context object. Module-level mutable singletons have no place in a tool handler.
Evidence
| 97 | def _set_redis_client(client: Optional[redis_lib.Redis]) -> None: |
| 98 | """Inject a Redis client โ used in tests (e.g. fakeredis). Pass None to reset.""" |
| 99 | global _redis_client |
| 100 | _redis_client = client |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server file uses Python's `global` keyword. `global` mutates module-level state from inside a function โ in a multi-tenant MCP server, this is almost always a cross-request data path. Closes the OWASP MCP Top 10:2025 MCP10 (Context Injection & Over-Sharing) gap. Fix: thread state through function arguments or a per-request context object. Module-level mutable singletons have no place in a tool handler.
Evidence
| 52 | def _get_frontend_corpus() -> list: |
| 53 | global _FRONTEND_CORPUS |
| 54 | if _FRONTEND_CORPUS is None: |
| 55 | try: |
| 56 | with open(_CORPUS_PATH) as f: |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server file uses Python's `global` keyword. `global` mutates module-level state from inside a function โ in a multi-tenant MCP server, this is almost always a cross-request data path. Closes the OWASP MCP Top 10:2025 MCP10 (Context Injection & Over-Sharing) gap. Fix: thread state through function arguments or a per-request context object. Module-level mutable singletons have no place in a tool handler.
Evidence
| 71 | def _get_redis() -> Optional[redis_lib.Redis]: |
| 72 | """Lazy Redis connection. Returns None if unavailable โ never raises.""" |
| 73 | global _redis_client |
| 74 | if _redis_client is not None: |
| 75 | return _redis_client |
| 76 | try: |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server holds a mutable shared container (cache / store / state / pool / registry / sessions / results / outputs) and mutates it via append / push / add / extend, but no caller-identity marker (user_id / session_id / caller_id / request_id / org_id / tenant_id / actor_id / subject / principal) appears anywhere in the file. A process-global list mutated from inside a tool handler with no caller partition leaks data across requests: a later caller can read what an earlier caller wrote. Closes
Evidence
| 1 | """ |
| 2 | datanexus/tools/t10.py โ T10 OSS Dependency & Vulnerability Intelligence. |
| 3 | |
| 4 | Spec: DataNexus_MCP_Spec_v7_3.docx Section 11.3 / Table 140 (authoritative) |
| 5 | |
| 6 | Exactly 5 data functions + 2 infrastructure stubs = 7 total. |
| 7 | |
| 8 | Data sources: |
| 9 | Primary: Google OSV.dev API (api.osv.dev/v1) โ Apache 2.0, no key. |
| 10 | Secondary: NIST NVD CVE API (services.nvd.nist.gov) โ public domain, no key. |
| 11 | Supporting: deps.dev API (api.deps.dev/v3alpha) โ Apache 2.0, no key. |
| 12 | |
| 13 | Hard stops (Section 12.5): |
| 14 | - NEVER return |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server file uses Python's `global` keyword. `global` mutates module-level state from inside a function โ in a multi-tenant MCP server, this is almost always a cross-request data path. Closes the OWASP MCP Top 10:2025 MCP10 (Context Injection & Over-Sharing) gap. Fix: thread state through function arguments or a per-request context object. Module-level mutable singletons have no place in a tool handler.
Evidence
| 59 | def _set_redis_client(client: Optional[redis_lib.Redis]) -> None: |
| 60 | """Inject a Redis client (e.g. fakeredis) for testing. Pass None to reset.""" |
| 61 | global _redis_client |
| 62 | _redis_client = client |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server holds a mutable shared container (cache / store / state / pool / registry / sessions / results / outputs) and mutates it via append / push / add / extend, but no caller-identity marker (user_id / session_id / caller_id / request_id / org_id / tenant_id / actor_id / subject / principal) appears anywhere in the file. A process-global list mutated from inside a tool handler with no caller partition leaks data across requests: a later caller can read what an earlier caller wrote. Closes
Evidence
| 1 | """ |
| 2 | datanexus/tools/nonprofit_sprint7.py โ Sprint 7 nonprofit depth tools. |
| 3 | |
| 4 | Tools: |
| 5 | search_nonprofits_by_category โ search US nonprofits by NTEE category + state |
| 6 | fetch_nonprofit_financial_trends โ multi-year revenue/expense/asset trends for a nonprofit |
| 7 | |
| 8 | OQ1 resolved: ProPublica /api/v2/organizations/{ein}.json returns pre-computed |
| 9 | fields (totrevenue, totfuncexpns, totprgmrevnue, netassetsend, tax_prd_yr) in |
| 10 | filings_with_data. No raw 990 JSON parsing needed. |
| 11 | |
| 12 | Circuit breaker: _propublica_br |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server holds a mutable shared container (cache / store / state / pool / registry / sessions / results / outputs) and mutates it via append / push / add / extend, but no caller-identity marker (user_id / session_id / caller_id / request_id / org_id / tenant_id / actor_id / subject / principal) appears anywhere in the file. A process-global list mutated from inside a tool handler with no caller partition leaks data across requests: a later caller can read what an earlier caller wrote. Closes
Evidence
| 1 | """ |
| 2 | datanexus/tools/security_sprint6.py โ Sprint 6 security tools. |
| 3 | |
| 4 | Tools: |
| 5 | fetch_package_maintainer_history โ maintainer health + anomaly score |
| 6 | fetch_package_risk_brief โ SHIP/CAUTION/BLOCK aggregator |
| 7 | detect_typosquatting โ Damerau-Levenshtein vs top-10k (added in final step) |
| 8 | |
| 9 | All are thin MCP wrappers. Logic lives in _security_utils.py / _maintainer_utils.py. |
| 10 | HTTP self-calls are forbidden โ utilities are called directly. |
| 11 | """ |
| 12 | |
| 13 | import asyncio |
| 14 | import logging |
| 15 | import tim |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server file uses Python's `global` keyword. `global` mutates module-level state from inside a function โ in a multi-tenant MCP server, this is almost always a cross-request data path. Closes the OWASP MCP Top 10:2025 MCP10 (Context Injection & Over-Sharing) gap. Fix: thread state through function arguments or a per-request context object. Module-level mutable singletons have no place in a tool handler.
Evidence
| 67 | connection is attempted rather than returning a broken client whose write errors |
| 68 | would be silently swallowed by the outer try/except in report_feedback(). |
| 69 | """ |
| 70 | global _redis_client |
| 71 | if _redis_client is not None: |
| 72 | try: |
| 73 | _redis_client.ping() |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server file uses Python's `global` keyword. `global` mutates module-level state from inside a function โ in a multi-tenant MCP server, this is almost always a cross-request data path. Closes the OWASP MCP Top 10:2025 MCP10 (Context Injection & Over-Sharing) gap. Fix: thread state through function arguments or a per-request context object. Module-level mutable singletons have no place in a tool handler.
Evidence
| 65 | def _set_caller_id(caller_id: Optional[str]) -> None: |
| 66 | """Inject a fixed caller_id for testing. Pass None to reset.""" |
| 67 | global _test_caller_id |
| 68 | _test_caller_id = caller_id |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server holds a mutable shared container (cache / store / state / pool / registry / sessions / results / outputs) and mutates it via append / push / add / extend, but no caller-identity marker (user_id / session_id / caller_id / request_id / org_id / tenant_id / actor_id / subject / principal) appears anywhere in the file. A process-global list mutated from inside a tool handler with no caller partition leaks data across requests: a later caller can read what an earlier caller wrote. Closes
Evidence
| 1 | """ |
| 2 | datanexus/tools/t04.py โ T04 IRS 990 / Nonprofit Data tool. |
| 3 | |
| 4 | Spec: DataNexus_MCP_Spec_v7_3.docx Section 12.4 / Phase 2 Step B |
| 5 | |
| 6 | Exactly 3 data functions + 2 infrastructure stubs = 5 total. |
| 7 | (Section 11.3, Table 163 โ authoritative signatures) |
| 8 | |
| 9 | Data sources: |
| 10 | Primary: IRS EO BMF (irs.gov) โ public domain |
| 11 | Secondary: IRS TEOS bulk downloads (irs.gov) โ public domain |
| 12 | Tertiary: UK Charity Commission public bulk extract (no auth required) |
| 13 | ccewuksprdoneregsadata1.blob.core.windo |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
MCP server file uses Python's `global` keyword. `global` mutates module-level state from inside a function โ in a multi-tenant MCP server, this is almost always a cross-request data path. Closes the OWASP MCP Top 10:2025 MCP10 (Context Injection & Over-Sharing) gap. Fix: thread state through function arguments or a per-request context object. Module-level mutable singletons have no place in a tool handler.
Evidence
| 58 | def _get_redis() -> Optional[redis_lib.Redis]: |
| 59 | """Lazy Redis connection. Returns None if unavailable โ never raises.""" |
| 60 | global _redis_client |
| 61 | if _redis_client is not None: |
| 62 | return _redis_client |
| 63 | try: |
Remediation
Partition shared state by caller identity, or eliminate it. Wrong: _cache = {} @mcp.tool() def search(query: str) -> list: if query in _cache: return _cache[query] result = _expensive(query) _cache[query] = result return result Right (key by caller): _cache: dict[str, dict] = {} @mcp.tool() def search(query: str, ctx) -> list: user_cache = _cache.setdefault(ctx.user_id, {}) if query in user_cache:
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
| 223 | try: |
| 224 | r = await get_redis() |
| 225 | if r: |
| 226 | await r.set(cache_key, tier, ex=300) |
| 227 | except Exception: |
| 228 | pass |
| 229 | return tier |
| 230 | |
| 231 | except Exception as exc: |
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
| 99 | # remaining allowlist domains โ any path counts |
| 100 | for allowed in _PATCH_ALLOWLIST: |
| 101 | if host == allowed or host.endswith("." + allowed): |
| 102 | return True |
| 103 | except Exception: |
| 104 | pass |
| 105 | return 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.
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
| 1184 | raw = r.hget(key_feedback(tool_id, rid), "data") |
| 1185 | if raw: |
| 1186 | try: |
| 1187 | records.append(json.loads(raw)) |
| 1188 | except Exception: |
| 1189 | pass |
| 1190 | except Exception: |
| 1191 | pass |
| 1192 | results[tool_id] = records |
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
| 59 | try: |
| 60 | r = _get_redis() |
| 61 | if r: |
| 62 | r.set(LAST_ERROR_KEY, msg[:500], ex=7 * 86400) |
| 63 | except Exception: |
| 64 | pass |
| 65 | |
| 66 | |
| 67 | async def refresh() -> bool: |
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
| 1186 | try: |
| 1187 | records.append(json.loads(raw)) |
| 1188 | except Exception: |
| 1189 | pass |
| 1190 | except Exception: |
| 1191 | pass |
| 1192 | results[tool_id] = records |
| 1193 | |
| 1194 | return JSONResponse({"feedback": results}) |
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
| 189 | pipe = r.pipeline(transaction=False) |
| 190 | |
| 191 | try: |
| 192 | pipe.execute() |
| 193 | except Exception: |
| 194 | pass |
| 195 | |
| 196 | return count |
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
| 448 | for a in awards: |
| 449 | ag = a.get("agency") or "Unknown" |
| 450 | try: |
| 451 | agency_totals[ag] = agency_totals.get(ag, 0.0) + float(a.get("amount") or 0) |
| 452 | except (TypeError, ValueError): |
| 453 | pass |
| 454 | top_agencies = sorted(agency_totals.items(), key=lambda x: x[1], reverse=True)[:5] |
| 455 | |
| 456 | rows = [] |
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
| 570 | return purls |
| 571 | finally: |
| 572 | try: |
| 573 | os.unlink(fname) |
| 574 | except OSError: |
| 575 | pass |
| 576 | |
| 577 | |
| 578 | # โโ OSV audit โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
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
| 84 | result = [] |
| 85 | for raw in raw_list: |
| 86 | try: |
| 87 | result.append(json.loads(raw)) |
| 88 | except Exception: |
| 89 | pass |
| 90 | return result |
| 91 | except Exception as exc: |
| 92 | log.warning("daily_digest: error reading agent gaps โ %s", exc) |
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
| 167 | """Flush PostHog queue on server shutdown.""" |
| 168 | if _ph: |
| 169 | try: |
| 170 | _ph.shutdown() |
| 171 | except Exception: |
| 172 | pass |
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
| 163 | key = f"datanexus:calls:{tool_id}:{today}" |
| 164 | try: |
| 165 | r.incr(key) |
| 166 | r.expire(key, 35 * 86400) |
| 167 | except Exception: |
| 168 | pass |
| 169 | |
| 170 | |
| 171 | # โโ EPO OAuth token management โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
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
| 435 | pipe = r.pipeline(transaction=False) |
| 436 | |
| 437 | try: |
| 438 | pipe.execute() |
| 439 | except Exception: |
| 440 | pass |
| 441 | |
| 442 | return count, sample |
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
| 124 | return purls |
| 125 | finally: |
| 126 | try: |
| 127 | os.unlink(fname) |
| 128 | except OSError: |
| 129 | pass |
| 130 | except Exception: |
| 131 | pass |
| 132 | # Fallback: manual extraction from SPDX JSON |
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
| 300 | pipe = r.pipeline(transaction=False) |
| 301 | |
| 302 | try: |
| 303 | pipe.execute() |
| 304 | except Exception: |
| 305 | pass |
| 306 | |
| 307 | return count |
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
| 573 | if path.startswith("node_modules/"): |
| 574 | name = path[len("node_modules/"):] |
| 575 | pinned[name] = info.get("version", "") |
| 576 | return pinned |
| 577 | except json.JSONDecodeError: |
| 578 | pass |
| 579 | # yarn.lock: simple regex extraction |
| 580 | pattern = re.compile(r'^"?(.+?)@[^:]+:\n\s+version "([^"]+)"', re.MULTILINE) |
| 581 | for m in pattern.finditer(lockfile): |
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
| 22 | if _failure_classifier is None: |
| 23 | try: |
| 24 | from datanexus.core import failure_classifier as _fc |
| 25 | _failure_classifier = _fc |
| 26 | except Exception: |
| 27 | pass |
| 28 | return _failure_classifier |
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
| 131 | try: |
| 132 | if is_re_signup and old_key_hash: |
| 133 | await r.delete(f"dn:apikey:{old_key_hash}") |
| 134 | await r.set(f"dn:apikey:{key_hash}", "free", ex=_KEY_CACHE_TTL) |
| 135 | except Exception: |
| 136 | pass |
| 137 | |
| 138 | # โโ 4. Send email via SendGrid โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
| 139 | email_sent = 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.
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
| 82 | if r is not None: |
| 83 | cache_key = f"datanexus:epo:token:{expiry_ts}" |
| 84 | try: |
| 85 | r.setex(cache_key, expires_in, token) |
| 86 | except Exception: |
| 87 | pass |
| 88 | |
| 89 | record_success_sync("epo_ops") |
| 90 | token_bytes = resp.content |
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
| 656 | if raw: |
| 657 | record = json.loads(raw) |
| 658 | if name_upper in record.get("name", "").upper(): |
| 659 | return record |
| 660 | except Exception: |
| 661 | pass |
| 662 | |
| 663 | # Slow fallback: bulk extract search |
| 664 | results = await search_uk_charity_bulk_by_name(name, limit=1) |
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
| 114 | key = f"datanexus:calls:{tool_id}:{today}" |
| 115 | try: |
| 116 | r.incr(key) |
| 117 | r.expire(key, 35 * 86400) |
| 118 | except Exception: |
| 119 | pass |
| 120 | |
| 121 | |
| 122 | def _sam_gov_key() -> 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
| 179 | key = f"datanexus:calls:{tool_id}:{today}" |
| 180 | try: |
| 181 | r.incr(key) |
| 182 | r.expire(key, 35 * 86400) |
| 183 | except Exception: |
| 184 | pass |
| 185 | |
| 186 | |
| 187 | def _regs_gov_key() -> 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
| 68 | result = [] |
| 69 | for raw in raw_list: |
| 70 | try: |
| 71 | result.append(json.loads(raw)) |
| 72 | except Exception: |
| 73 | pass |
| 74 | return result |
| 75 | except Exception as exc: |
| 76 | log.warning("daily_digest: error reading failures โ %s", exc) |
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
| 1575 | data = resp.json() |
| 1576 | answers = data.get("Answer", []) |
| 1577 | if answers: |
| 1578 | return selector |
| 1579 | except Exception: |
| 1580 | pass |
| 1581 | return None |
| 1582 | |
| 1583 | tasks = [_check_one(sel) for sel in selectors] |
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
| 1772 | if not vector: |
| 1773 | return "UNKNOWN" |
| 1774 | try: |
| 1775 | return _score_to_level(float(vector)) |
| 1776 | except (ValueError, TypeError): |
| 1777 | pass |
| 1778 | raw = vector.upper() |
| 1779 | for prefix in ("CVSS:3.1/", "CVSS:3.0/", "CVSS:2.0/"): |
| 1780 | if raw.startswith(prefix): |
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
| 221 | # Fast path: bare numeric score (e.g. stored as "7.5") |
| 222 | try: |
| 223 | return _score_to_level(float(vector)) |
| 224 | except (ValueError, TypeError): |
| 225 | pass |
| 226 | |
| 227 | raw = vector.upper() |
| 228 | for prefix in ("CVSS:3.1/", "CVSS:3.0/", "CVSS:2.0/"): |
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
| 531 | try: |
| 532 | raw = r.get(f"datanexus:T04:bmf:{ein_clean}") |
| 533 | if raw: |
| 534 | return json.loads(raw) |
| 535 | except Exception: |
| 536 | pass |
| 537 | |
| 538 | # 2. Live CSV stream fallback (BMF worker not yet run) |
| 539 | return await _lookup_ein_csv_live(ein_clean) |
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
| 1082 | count_key = f"datanexus:ht:daily_count:{day_key}" |
| 1083 | current = _r.get(count_key) |
| 1084 | if current is not None and int(current) >= _HT_DAILY_LIMIT: |
| 1085 | quota_exceeded = True |
| 1086 | except Exception: |
| 1087 | pass |
| 1088 | |
| 1089 | if quota_exceeded: |
| 1090 | return error_response( |
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
| 156 | exc_info=exc_info, |
| 157 | user_agent=user_agent, |
| 158 | exc_type=exc_type, |
| 159 | ) |
| 160 | except Exception: |
| 161 | pass # classifier must never affect the response |
| 162 | |
| 163 | return result |
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
| 417 | for result in data.get("results", [])[:20]: |
| 418 | a = _parse_usaspending_result(result) |
| 419 | try: |
| 420 | total_amount += float(a.get("amount") or 0) |
| 421 | except (TypeError, ValueError): |
| 422 | pass |
| 423 | awards.append(a) |
| 424 | source_used = "USASpending.gov" |
| 425 | record_success_sync("usaspending") |
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
| 174 | if sig in BUG_SIGNALS: |
| 175 | bugs += 1 |
| 176 | elif sig in IMPROVEMENT_SIGNALS: |
| 177 | improvements += 1 |
| 178 | except Exception: |
| 179 | pass |
| 180 | except Exception: |
| 181 | pass |
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
| 324 | # โโ Form 1: bare numeric score โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
| 325 | try: |
| 326 | return _score_to_level(float(vector)) |
| 327 | except (ValueError, TypeError): |
| 328 | pass |
| 329 | |
| 330 | # โโ Parse metrics dict from vector string โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
| 331 | # Strip "CVSS:3.x/" prefix if present |
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
| 253 | "bytes_used": total, |
| 254 | "limit": _EPO_BYTES_LIMIT, |
| 255 | "month": month_iso, |
| 256 | })) |
| 257 | except Exception: |
| 258 | pass |
| 259 | |
| 260 | |
| 261 | # โโ EPO response normalisation โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
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
| 120 | key = f"datanexus:calls:{tool_id}:{today}" |
| 121 | try: |
| 122 | r.incr(key) |
| 123 | r.expire(key, 35 * 86400) |
| 124 | except Exception: |
| 125 | pass |
| 126 | |
| 127 | |
| 128 | # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
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
| 169 | if sig in BUG_SIGNALS: |
| 170 | bugs += 1 |
| 171 | elif sig in IMPROVEMENT_SIGNALS: |
| 172 | improvements += 1 |
| 173 | except Exception: |
| 174 | pass |
| 175 | except Exception as exc: |
| 176 | log.warning("dashboard: feedback read error tool=%s โ %s", tool_id, exc) |
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
| 220 | if r is not None and token: |
| 221 | cache_key = f"datanexus:epo:token:{expiry_ts}" |
| 222 | try: |
| 223 | r.setex(cache_key, expires_in, token) |
| 224 | except Exception: |
| 225 | pass |
| 226 | |
| 227 | return token or None |
| 228 | except Exception as exc: |
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
| 146 | "tool": self.tool_id, |
| 147 | "source": self.source_id, |
| 148 | "validation_issues": _issues, |
| 149 | })) |
| 150 | except (json.JSONDecodeError, ValueError): |
| 151 | pass # non-JSON payload โ validation skipped, proceed normally |
| 152 | |
| 153 | # Store raw bytes under a source-keyed cache entry |
| 154 | # Subclasses call set_cached with their own fine-grained keys; |
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
| 130 | log.warning("prewarm: gather error โ %s", exc) |
| 131 | finally: |
| 132 | try: |
| 133 | await r.aclose() |
| 134 | except Exception: |
| 135 | pass |
| 136 | |
| 137 | log.info("prewarm: completed for tools %s", targets) |
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
| 1154 | try: |
| 1155 | count_key = f"datanexus:ht:daily_count:{day_key}" |
| 1156 | _r.incr(count_key) |
| 1157 | _r.expire(count_key, _HT_QUOTA_TTL) |
| 1158 | except Exception: |
| 1159 | pass |
| 1160 | |
| 1161 | result = { |
| 1162 | "ip": ip, |
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
| 1119 | fetched_dt = datetime.fromisoformat(fetched_at_raw) |
| 1120 | age_h = (datetime.now(timezone.utc) - fetched_dt).total_seconds() / 3600 |
| 1121 | if age_h > _KEV_STALE_H: |
| 1122 | stale_warning = "KEV catalog may be stale" |
| 1123 | except Exception: |
| 1124 | pass |
| 1125 | |
| 1126 | # catalog_raw is a dict (from get_cached which json.loads) |
| 1127 | if isinstance(catalog_raw, dict) and "vulnerabilities" in catalog_raw: |
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
| 534 | async with httpx.AsyncClient(timeout=_HTTP_TIMEOUT, headers=_HTTP_HEADERS, follow_redirects=True) as c: |
| 535 | resp = await c.get(url) |
| 536 | if resp.status_code == 200: |
| 537 | return resp.json().get("downloads") |
| 538 | except Exception: |
| 539 | pass |
| 540 | return 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
| 631 | try: |
| 632 | raw = r.get(f"datanexus:T04:uk:{regno}") |
| 633 | if raw: |
| 634 | return json.loads(raw) |
| 635 | except Exception: |
| 636 | pass |
| 637 | |
| 638 | # Slow fallback: bulk extract download (no auth, ~30-40s, one-time per boot) |
| 639 | return await fetch_uk_charity_bulk_single(regno) |
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
| 120 | except Exception as exc: |
| 121 | log.warning("signup: DB operation failed: %s", exc) |
| 122 | try: |
| 123 | await pool.close() |
| 124 | except Exception: |
| 125 | pass |
| 126 | return JSONResponse({"error": "service_unavailable"}, status_code=503) |
| 127 | |
| 128 | # Cache new key hash so _ApiKeyMiddleware picks it up within the TTL window |
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
| 546 | """Replicate the verdict logic from security_sprint6._compute_verdict.""" |
| 547 | try: |
| 548 | from datanexus.tools.security_sprint6 import _compute_verdict as _cv |
| 549 | return _cv(critical_cve_count, high_cve_count, licence_risk, maintainer_health) |
| 550 | except Exception: |
| 551 | pass |
| 552 | # Fallback |
| 553 | if critical_cve_count and critical_cve_count > 0: |
| 554 | return "BLOCK", "Critical CVE found in package." |
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
| 1325 | if r: |
| 1326 | try: |
| 1327 | r.ping() |
| 1328 | redis_ok = True |
| 1329 | except Exception: |
| 1330 | pass |
| 1331 | |
| 1332 | return JSONResponse({ |
| 1333 | "status": "ok", |
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
| 214 | try: |
| 215 | r = await get_redis() |
| 216 | if r: |
| 217 | await r.set(cache_key, "revoked", ex=300) |
| 218 | except Exception: |
| 219 | pass |
| 220 | return None |
| 221 | |
| 222 | tier = row["tier"] |
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
| 92 | try: |
| 93 | from cyclonedx.model.bom import Bom |
| 94 | bom = Bom.from_json(data=raw) |
| 95 | return [str(c.purl) for c in bom.components if c.purl] |
| 96 | except Exception: |
| 97 | pass |
| 98 | # Fallback: manual extraction |
| 99 | purls = [] |
| 100 | for comp in raw.get("components", []): |
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
| 198 | if expiry_ts > now + 60: # 60s buffer |
| 199 | token = r.get(key) |
| 200 | if token: |
| 201 | return token |
| 202 | except Exception: |
| 203 | pass |
| 204 | |
| 205 | # Fetch new token |
| 206 | try: |
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
| 131 | key = f"datanexus:calls:{tool_id}:{today}" |
| 132 | try: |
| 133 | r.incr(key) |
| 134 | r.expire(key, 35 * 86400) |
| 135 | except Exception: |
| 136 | pass |
| 137 | |
| 138 | |
| 139 | # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
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
| 176 | elif sig in IMPROVEMENT_SIGNALS: |
| 177 | improvements += 1 |
| 178 | except Exception: |
| 179 | pass |
| 180 | except Exception: |
| 181 | pass |
| 182 | |
| 183 | result["tools"][tool_id] = { |
| 184 | "total": total, |
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
| 100 | result = [] |
| 101 | for raw in raw_entries: |
| 102 | try: |
| 103 | result.append(json.loads(raw)) |
| 104 | except (json.JSONDecodeError, TypeError): |
| 105 | pass |
| 106 | return result |
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
| 126 | try: |
| 127 | os.unlink(fname) |
| 128 | except OSError: |
| 129 | pass |
| 130 | except Exception: |
| 131 | pass |
| 132 | # Fallback: manual extraction from SPDX JSON |
| 133 | try: |
| 134 | raw = json.loads(sbom_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
| 274 | raw_p99 = r.get(f"datanexus:p99:{tool_id}:{today}") |
| 275 | if raw_p99 is not None: |
| 276 | try: |
| 277 | p99_ms = float(raw_p99) |
| 278 | except ValueError: |
| 279 | pass |
| 280 | |
| 281 | # โโ top 5 params_hash (privacy-safe sorted set) โโโโโโโโโโโโโ |
| 282 | raw_top = r.zrevrange( |
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
| 305 | try: |
| 306 | lr = datetime.fromisoformat(last_release_str) |
| 307 | if lr < _18m_ago: |
| 308 | abandoned.append({"name": name, "last_release": last_release_str}) |
| 309 | except ValueError: |
| 310 | pass |
| 311 | |
| 312 | # Verdict logic |
| 313 | incompatible_licences = {r["name"] for r in licence_risks if r["risk"] == "INCOMPATIBLE"} |
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.