-
-
Notifications
You must be signed in to change notification settings - Fork 0
Fix 4 critical API bugs found through comprehensive E2E testing #167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
acaeadd
48536f9
1cfb734
178729d
585b4a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -468,6 +468,30 @@ def _process_design( | |
| buffer = text_stream.detach() # type: ignore[assignment] | ||
| if not rows: | ||
| raise HTTPException(status_code=400, detail="Design CSV contained no rows") | ||
|
|
||
| overlay: OverlayConfig = app.state.overlay | ||
| strict_validation = overlay.toggles.get("strict_validation", False) | ||
|
|
||
| if strict_validation: | ||
| required_columns = { | ||
| "component", | ||
| "subcomponent", | ||
| "owner", | ||
| "data_class", | ||
| "description", | ||
| "control_scope", | ||
| } | ||
| missing_columns = required_columns - set(columns) | ||
| if missing_columns: | ||
| raise HTTPException( | ||
| status_code=422, | ||
| detail={ | ||
| "message": "Design CSV missing required columns (strict mode)", | ||
| "missing_columns": sorted(missing_columns), | ||
| "required_columns": sorted(required_columns), | ||
| }, | ||
| ) | ||
|
|
||
| dataset = {"columns": columns, "rows": rows} | ||
| raw_bytes = _maybe_materialise_raw(buffer, total) | ||
| _store("design", dataset, original_filename=filename, raw_bytes=raw_bytes) | ||
|
|
@@ -483,9 +507,59 @@ def _process_design( | |
| def _process_sbom( | ||
| buffer: SpooledTemporaryFile, total: int, filename: str | ||
| ) -> Dict[str, Any]: | ||
| buffer.seek(0) | ||
| try: | ||
| sbom_data = json.load(buffer) | ||
| except json.JSONDecodeError as exc: | ||
| raise HTTPException( | ||
| status_code=400, detail=f"Invalid JSON in SBOM: {exc}" | ||
| ) from exc | ||
|
Comment on lines
483
to
+516
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new validation in Useful? React with 👍 / 👎. |
||
|
|
||
| overlay: OverlayConfig = app.state.overlay | ||
| strict_validation = overlay.toggles.get("strict_validation", False) | ||
|
|
||
| bom_format = sbom_data.get("bomFormat") | ||
| if bom_format and bom_format not in ("CycloneDX", "SPDX"): | ||
| if strict_validation: | ||
| raise HTTPException( | ||
| status_code=422, | ||
| detail={ | ||
| "message": f"Unsupported SBOM format: {bom_format}", | ||
| "supported_formats": ["CycloneDX", "SPDX"], | ||
| }, | ||
| ) | ||
| else: | ||
| logger.warning( | ||
| "SBOM has unsupported bomFormat: %s, continuing with provider fallback", | ||
| bom_format, | ||
| ) | ||
|
|
||
| if not bom_format: | ||
| components = sbom_data.get("components") | ||
| detected_manifests = sbom_data.get("detectedManifests") | ||
| artifacts = sbom_data.get("artifacts") | ||
| descriptor = sbom_data.get("descriptor") | ||
|
|
||
| has_known_format = ( | ||
| isinstance(components, list) | ||
| or isinstance(detected_manifests, dict) | ||
| or isinstance(artifacts, list) | ||
| or isinstance(descriptor, dict) | ||
| ) | ||
|
|
||
| if not has_known_format and strict_validation: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Prompt for AI agents |
||
| raise HTTPException( | ||
| status_code=422, | ||
| detail={ | ||
| "message": "SBOM missing bomFormat and has unrecognized structure", | ||
| "hint": "Provide bomFormat field or use a known format (CycloneDX, GitHub dependency snapshot, Syft)", | ||
| }, | ||
| ) | ||
|
|
||
| buffer.seek(0) | ||
| try: | ||
| sbom: NormalizedSBOM = normalizer.load_sbom(buffer) | ||
| except Exception as exc: # pragma: no cover - pass to FastAPI | ||
| except Exception as exc: | ||
| logger.exception("SBOM normalisation failed") | ||
| raise HTTPException( | ||
| status_code=400, detail=f"Failed to parse SBOM: {exc}" | ||
|
|
@@ -508,11 +582,27 @@ def _process_cve( | |
| ) -> Dict[str, Any]: | ||
| try: | ||
| cve_feed: NormalizedCVEFeed = normalizer.load_cve_feed(buffer) | ||
| except Exception as exc: # pragma: no cover - FastAPI serialises | ||
| except Exception as exc: | ||
| logger.exception("CVE feed normalisation failed") | ||
| raise HTTPException( | ||
| status_code=400, detail=f"Failed to parse CVE feed: {exc}" | ||
| ) from exc | ||
|
|
||
| overlay: OverlayConfig = app.state.overlay | ||
| strict_validation = overlay.toggles.get("strict_validation", False) | ||
|
|
||
| if cve_feed.errors and strict_validation: | ||
| raise HTTPException( | ||
| status_code=422, | ||
| detail={ | ||
| "message": "CVE feed contains validation errors (strict mode)", | ||
| "record_count": cve_feed.metadata.get("record_count", 0), | ||
| "validation_errors": cve_feed.errors[:10], | ||
| "total_errors": len(cve_feed.errors), | ||
| "hint": "Use official CVE JSON 5.1.1 format or ensure all required fields are present", | ||
| }, | ||
| ) | ||
|
|
||
| raw_bytes = _maybe_materialise_raw(buffer, total) | ||
| _store("cve", cve_feed, original_filename=filename, raw_bytes=raw_bytes) | ||
| return { | ||
|
|
@@ -911,6 +1001,11 @@ async def run_pipeline() -> Dict[str, Any]: | |
| context=app.state.artifacts.get("context"), | ||
| ) | ||
| result["run_id"] = run_id | ||
|
|
||
| severity_overview = result.get("severity_overview", {}) | ||
| guardrail_evaluation = result.get("guardrail_evaluation", {}) | ||
| result["highest_severity"] = severity_overview.get("highest") | ||
| result["guardrail_status"] = guardrail_evaluation.get("status") | ||
| analytics_store = getattr(app.state, "analytics_store", None) | ||
| if analytics_store is not None: | ||
| try: | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,259 @@ | ||||||
| { | ||||||
| "generated": "2024-10-28T12:00:00Z", | ||||||
| "source": "NVD + KEV + EPSS", | ||||||
| "cves": [ | ||||||
| { | ||||||
| "id": "CVE-2025-0001", | ||||||
| "package": "pg", | ||||||
| "version": "8.9.0", | ||||||
| "cvss": 9.8, | ||||||
| "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", | ||||||
| "severity": "CRITICAL", | ||||||
| "published": "2024-10-01T00:00:00Z", | ||||||
| "summary": "Remote Code Execution via malformed SQL query in PostgreSQL Node.js driver", | ||||||
| "description": "A critical vulnerability in the pg (node-postgres) driver allows remote code execution through specially crafted SQL queries. The vulnerability exists in the query parsing logic and can be exploited without authentication.", | ||||||
| "cwe": ["CWE-94"], | ||||||
| "references": [ | ||||||
| "https://nvd.nist.gov/vuln/detail/CVE-2025-0001", | ||||||
| "https://github.com/brianc/node-postgres/security/advisories/GHSA-xxxx-yyyy-zzzz" | ||||||
| ], | ||||||
| "epss_score": 0.89, | ||||||
| "epss_percentile": 0.98, | ||||||
| "kev_listed": true, | ||||||
| "kev_date_added": "2024-10-15", | ||||||
| "kev_due_date": "2024-11-05", | ||||||
| "kev_required_action": "Apply updates per vendor instructions or discontinue use of the product if updates are unavailable.", | ||||||
| "kev_known_ransomware": true, | ||||||
| "exploit_available": true, | ||||||
| "exploit_maturity": "functional", | ||||||
| "patch_available": true, | ||||||
| "fixed_version": "8.11.3" | ||||||
| }, | ||||||
| { | ||||||
| "id": "CVE-2024-1709", | ||||||
| "package": "express", | ||||||
| "version": "4.18.2", | ||||||
| "cvss": 7.5, | ||||||
| "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", | ||||||
| "severity": "HIGH", | ||||||
| "published": "2024-05-15T00:00:00Z", | ||||||
| "summary": "Authentication bypass in Express.js middleware chain", | ||||||
| "description": "An authentication bypass vulnerability exists in Express.js when using certain middleware configurations. Attackers can bypass authentication checks by manipulating request headers.", | ||||||
| "cwe": ["CWE-287"], | ||||||
| "references": [ | ||||||
| "https://nvd.nist.gov/vuln/detail/CVE-2024-1709", | ||||||
| "https://github.com/expressjs/express/security/advisories/GHSA-abcd-efgh-ijkl" | ||||||
| ], | ||||||
| "epss_score": 0.72, | ||||||
| "epss_percentile": 0.94, | ||||||
| "kev_listed": true, | ||||||
| "kev_date_added": "2024-06-01", | ||||||
| "kev_due_date": "2024-06-22", | ||||||
| "kev_required_action": "Apply mitigations per vendor instructions or discontinue use of the product if mitigations are unavailable.", | ||||||
| "kev_known_ransomware": false, | ||||||
| "exploit_available": true, | ||||||
| "exploit_maturity": "proof-of-concept", | ||||||
| "patch_available": true, | ||||||
| "fixed_version": "4.19.2" | ||||||
| }, | ||||||
| { | ||||||
| "id": "CVE-2024-2890", | ||||||
| "package": "lodash", | ||||||
| "version": "4.17.20", | ||||||
| "cvss": 7.4, | ||||||
| "cvss_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N", | ||||||
| "severity": "HIGH", | ||||||
| "published": "2024-07-20T00:00:00Z", | ||||||
| "summary": "Prototype Pollution in lodash", | ||||||
| "description": "A prototype pollution vulnerability in lodash allows attackers to modify Object.prototype properties, potentially leading to remote code execution or denial of service.", | ||||||
| "cwe": ["CWE-1321"], | ||||||
| "references": [ | ||||||
| "https://nvd.nist.gov/vuln/detail/CVE-2024-2890", | ||||||
| "https://github.com/lodash/lodash/security/advisories/GHSA-mnop-qrst-uvwx" | ||||||
| ], | ||||||
| "epss_score": 0.68, | ||||||
| "epss_percentile": 0.91, | ||||||
| "kev_listed": false, | ||||||
| "exploit_available": true, | ||||||
| "exploit_maturity": "functional", | ||||||
| "patch_available": true, | ||||||
| "fixed_version": "4.17.21" | ||||||
| }, | ||||||
| { | ||||||
| "id": "CVE-2024-5629", | ||||||
| "package": "axios", | ||||||
| "version": "1.6.0", | ||||||
| "cvss": 6.5, | ||||||
| "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N", | ||||||
| "severity": "MEDIUM", | ||||||
| "published": "2024-08-10T00:00:00Z", | ||||||
| "summary": "Server-Side Request Forgery (SSRF) in axios", | ||||||
| "description": "An SSRF vulnerability in axios allows attackers to make requests to internal network resources by manipulating the URL parameter.", | ||||||
| "cwe": ["CWE-918"], | ||||||
| "references": [ | ||||||
| "https://nvd.nist.gov/vuln/detail/CVE-2024-5629", | ||||||
| "https://github.com/axios/axios/security/advisories/GHSA-ssrf-1234-5678" | ||||||
| ], | ||||||
| "epss_score": 0.42, | ||||||
| "epss_percentile": 0.78, | ||||||
| "kev_listed": false, | ||||||
| "exploit_available": false, | ||||||
| "exploit_maturity": "unproven", | ||||||
| "patch_available": true, | ||||||
| "fixed_version": "1.6.2" | ||||||
| }, | ||||||
| { | ||||||
| "id": "CVE-2024-7348", | ||||||
| "package": "jsonwebtoken", | ||||||
| "version": "9.0.2", | ||||||
| "cvss": 5.9, | ||||||
| "cvss_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", | ||||||
| "severity": "MEDIUM", | ||||||
| "published": "2024-09-05T00:00:00Z", | ||||||
| "summary": "JWT signature verification bypass", | ||||||
| "description": "A vulnerability in jsonwebtoken allows attackers to bypass signature verification under certain conditions, potentially leading to authentication bypass.", | ||||||
| "cwe": ["CWE-347"], | ||||||
| "references": [ | ||||||
| "https://nvd.nist.gov/vuln/detail/CVE-2024-7348", | ||||||
| "https://github.com/auth0/node-jsonwebtoken/security/advisories/GHSA-jwt1-2345-6789" | ||||||
| ], | ||||||
| "epss_score": 0.38, | ||||||
| "epss_percentile": 0.72, | ||||||
| "kev_listed": false, | ||||||
| "exploit_available": false, | ||||||
| "exploit_maturity": "unproven", | ||||||
| "patch_available": true, | ||||||
| "fixed_version": "9.0.3" | ||||||
| }, | ||||||
| { | ||||||
| "id": "CVE-2024-8421", | ||||||
| "package": "redis", | ||||||
| "version": "4.6.10", | ||||||
| "cvss": 5.3, | ||||||
| "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", | ||||||
| "severity": "MEDIUM", | ||||||
| "published": "2024-09-20T00:00:00Z", | ||||||
| "summary": "Denial of Service in Redis client", | ||||||
| "description": "A denial of service vulnerability in the Redis Node.js client allows attackers to cause resource exhaustion through malformed commands.", | ||||||
| "cwe": ["CWE-400"], | ||||||
| "references": [ | ||||||
| "https://nvd.nist.gov/vuln/detail/CVE-2024-8421", | ||||||
| "https://github.com/redis/node-redis/security/advisories/GHSA-redis-dos-1234" | ||||||
| ], | ||||||
| "epss_score": 0.15, | ||||||
| "epss_percentile": 0.52, | ||||||
| "kev_listed": false, | ||||||
| "exploit_available": false, | ||||||
| "exploit_maturity": "unproven", | ||||||
| "patch_available": true, | ||||||
| "fixed_version": "4.6.11" | ||||||
| }, | ||||||
| { | ||||||
| "id": "CVE-2024-9102", | ||||||
| "package": "helmet", | ||||||
| "version": "7.1.0", | ||||||
| "cvss": 4.3, | ||||||
| "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N", | ||||||
| "severity": "MEDIUM", | ||||||
| "published": "2024-10-01T00:00:00Z", | ||||||
| "summary": "Content Security Policy bypass in helmet", | ||||||
| "description": "A CSP bypass vulnerability in helmet allows attackers to inject malicious scripts despite CSP headers being set.", | ||||||
| "cwe": ["CWE-693"], | ||||||
| "references": [ | ||||||
| "https://nvd.nist.gov/vuln/detail/CVE-2024-9102", | ||||||
| "https://github.com/helmetjs/helmet/security/advisories/GHSA-csp-bypass-1234" | ||||||
| ], | ||||||
| "epss_score": 0.08, | ||||||
| "epss_percentile": 0.35, | ||||||
| "kev_listed": false, | ||||||
| "exploit_available": false, | ||||||
| "exploit_maturity": "unproven", | ||||||
| "patch_available": true, | ||||||
| "fixed_version": "7.1.1" | ||||||
| }, | ||||||
| { | ||||||
| "id": "CVE-2024-31449", | ||||||
| "package": "openssl", | ||||||
| "version": "3.1.4", | ||||||
| "cvss": 7.5, | ||||||
| "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", | ||||||
| "severity": "HIGH", | ||||||
| "published": "2024-04-08T00:00:00Z", | ||||||
| "summary": "Denial of Service in OpenSSL", | ||||||
| "description": "A vulnerability in OpenSSL's SSL/TLS implementation can cause a denial of service through excessive memory consumption.", | ||||||
| "cwe": ["CWE-400"], | ||||||
| "references": [ | ||||||
| "https://nvd.nist.gov/vuln/detail/CVE-2024-31449", | ||||||
| "https://www.openssl.org/news/secadv/20240408.txt" | ||||||
| ], | ||||||
| "epss_score": 0.55, | ||||||
| "epss_percentile": 0.85, | ||||||
| "kev_listed": false, | ||||||
| "exploit_available": true, | ||||||
| "exploit_maturity": "proof-of-concept", | ||||||
| "patch_available": true, | ||||||
| "fixed_version": "3.1.5" | ||||||
| }, | ||||||
| { | ||||||
| "id": "CVE-2023-44487", | ||||||
| "package": "node", | ||||||
| "version": "18.18.2", | ||||||
| "cvss": 7.5, | ||||||
| "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", | ||||||
| "severity": "HIGH", | ||||||
| "published": "2023-10-10T00:00:00Z", | ||||||
| "summary": "HTTP/2 Rapid Reset Attack", | ||||||
| "description": "The HTTP/2 protocol allows a denial of service (server resource consumption) because request cancellation can reset many streams quickly.", | ||||||
| "cwe": ["CWE-400"], | ||||||
| "references": [ | ||||||
| "https://nvd.nist.gov/vuln/detail/CVE-2023-44487", | ||||||
| "https://nodejs.org/en/blog/vulnerability/october-2023-security-releases" | ||||||
| ], | ||||||
| "epss_score": 0.91, | ||||||
| "epss_percentile": 0.99, | ||||||
| "kev_listed": true, | ||||||
| "kev_date_added": "2023-10-10", | ||||||
| "kev_due_date": "2023-10-31", | ||||||
| "kev_required_action": "Apply mitigations per vendor instructions or discontinue use of the product if mitigations are unavailable.", | ||||||
| "kev_known_ransomware": false, | ||||||
| "exploit_available": true, | ||||||
| "exploit_maturity": "functional", | ||||||
| "patch_available": true, | ||||||
| "fixed_version": "18.18.3" | ||||||
| }, | ||||||
| { | ||||||
| "id": "CVE-2024-28757", | ||||||
| "package": "alpine", | ||||||
| "version": "3.18.4", | ||||||
| "cvss": 6.2, | ||||||
| "cvss_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", | ||||||
| "severity": "MEDIUM", | ||||||
| "published": "2024-03-15T00:00:00Z", | ||||||
| "summary": "Local Denial of Service in Alpine Linux", | ||||||
| "description": "A vulnerability in Alpine Linux's package manager allows local attackers to cause a denial of service.", | ||||||
| "cwe": ["CWE-400"], | ||||||
| "references": [ | ||||||
| "https://nvd.nist.gov/vuln/detail/CVE-2024-28757", | ||||||
| "https://gitlab.alpinelinux.org/alpine/aports/-/issues/15678" | ||||||
| ], | ||||||
| "epss_score": 0.04, | ||||||
| "epss_percentile": 0.18, | ||||||
| "kev_listed": false, | ||||||
| "exploit_available": false, | ||||||
| "exploit_maturity": "unproven", | ||||||
| "patch_available": true, | ||||||
| "fixed_version": "3.18.5" | ||||||
| } | ||||||
| ], | ||||||
| "statistics": { | ||||||
| "total_cves": 10, | ||||||
| "critical": 1, | ||||||
| "high": 4, | ||||||
| "medium": 5, | ||||||
| "low": 0, | ||||||
| "kev_listed": 3, | ||||||
| "epss_high": 4, | ||||||
| "exploit_available": 6, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The statistics block reports 6 CVEs with exploit_available, but only 5 records have exploit_available set to true, so the aggregate count is inconsistent with the data and will mislead any validation that relies on these totals. Prompt for AI agents
Suggested change
|
||||||
| "patch_available": 10 | ||||||
| } | ||||||
| } | ||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
json.load(buffer)now runs for every SBOM upload, so ZIP/GZIP SBOMs trigger a JSONDecodeError and fail with HTTP 400. Please skip the JSON parsing for non-JSON inputs or branch on the content type before callingjson.load.Prompt for AI agents