SecBrief / backend /cli_scanner.py
“Peeyush
Feature 1 success
d87408e
Raw History Blame Contribute Delete
5.53 kB
import hashlib, json
from typing import List, Optional
def parse_mistral_json(raw):
import re
if not raw:
return None
text = raw.strip()
text = re.sub(r"^```(?:json)?", "", text, flags=re.MULTILINE).strip()
text = re.sub(r"```$", "", text, flags=re.MULTILINE).strip()
start = text.find("{")
end = text.rfind("}")
if start != -1 and end != -1:
text = text[start : end + 1]
return json.loads(text)
async def analyze_packages_with_mistral(packages, ecosystem, chat_mistral):
pkg_lines = "\n".join([f"- {p['name']} v{p['version']}" for p in packages])
prompt = f"""You are a security expert with deep knowledge of CVEs.
Analyze these {ecosystem} packages for known security vulnerabilities:
{pkg_lines}
Think through what you know about each package version, then provide your findings.
At the end, output ONLY a JSON block in this exact format wrapped in triple backticks:
````json
{{
"findings": [
{{
"package": "lodash",
"version": "4.17.4",
"severity": "HIGH",
"cve_ids": ["CVE-2019-10744", "CVE-2020-8203"],
"summary": "Prototype pollution vulnerability allows attackers to modify Object prototype",
"recommended_version": "4.17.21",
"owasp": "A06:2021-Vulnerable and Outdated Components"
}}
],
"total_scanned": {len(packages)},
"critical_count": 0,
"high_count": 0,
"medium_count": 0,
"low_count": 0,
"safe_count": 0
}}
````
Include ALL packages in findings array. Set severity to NONE for safe packages. Fill counts accurately."""
try:
result = chat_mistral(
"You are a security expert with deep knowledge of CVEs.",
prompt,
json_mode=False,
temperature=0.2,
)
if not result:
raise RuntimeError("Mistral is not configured (set MISTRAL_API_KEY) or request failed")
raw = result[0] if result else ""
parsed = parse_mistral_json(raw)
if parsed is None:
raise ValueError("Unable to parse JSON from Mistral response")
return parsed
except Exception as e:
return {"findings":[],"total_scanned":len(packages),"critical_count":0,"high_count":0,"medium_count":0,"low_count":0,"safe_count":len(packages),"error":str(e)}
async def analyze_container_with_mistral(image, sbom_packages, chat_mistral):
sbom = ""
if sbom_packages:
sbom = "\nSBOM:\n" + "\n".join([f"- {p['name']} {p['version']} ({p.get('ecosystem','')})" for p in sbom_packages])
prompt = f"""You are a container security expert with deep knowledge of Docker image CVEs.
Analyze this container image for security vulnerabilities:
Image: {image}{sbom}
Consider: known CVEs for this image version, base OS risks, EOL status, package vulnerabilities.
At the end, output ONLY a JSON block in this exact format wrapped in triple backticks:
````json
{{
"image": "{image}",
"base_os_guess": "Debian",
"uses_latest_tag": false,
"overall_risk": "HIGH",
"image_findings": [
{{
"component": "base image",
"severity": "HIGH",
"cve_ids": ["CVE-2021-33910"],
"summary": "systemd vulnerability in base Debian image"
}}
],
"package_findings": [],
"hardening_steps": [
"Upgrade to nginx:1.25 or later",
"Run as non-root user",
"Use distroless base image"
],
"critical_count": 0,
"high_count": 1,
"medium_count": 0,
"low_count": 0,
"total_findings": 1,
"owasp": "A06:2021-Vulnerable and Outdated Components"
}}
```"""
try:
result = chat_mistral(
"You are a container security expert with deep knowledge of Docker image CVEs.",
prompt,
json_mode=False,
temperature=0.2,
)
if not result:
raise RuntimeError("Mistral is not configured (set MISTRAL_API_KEY) or request failed")
raw = result[0] if result else ""
parsed = parse_mistral_json(raw)
if parsed is None:
raise ValueError("Unable to parse JSON from Mistral response")
return parsed
except Exception as e:
return {"image":image,"base_os_guess":"Unknown","uses_latest_tag":"latest" in image,"overall_risk":"UNKNOWN","image_findings":[],"package_findings":[],"hardening_steps":[],"critical_count":0,"high_count":0,"medium_count":0,"low_count":0,"total_findings":0,"error":str(e)}
def build_steps_packages(findings):
steps = [{"action":"remediate_vulnerable_package","resource":f"{f.get('package')}@{f.get('version')}","metadata":{"severity":f.get("severity"),"cve_ids":f.get("cve_ids",[]),"owasp":f.get("owasp","A06:2021")}} for f in findings if f.get("severity") in ("CRITICAL","HIGH","MEDIUM")]
return steps or [{"action":"no_action_required","resource":"package_scan","metadata":{}}]
def build_steps_container(image, result):
steps = [{"action":"patch_container_component","resource":f"{image}→{f.get('component',f.get('package','unknown'))}","metadata":{"severity":f.get("severity"),"cve_ids":f.get("cve_ids",[])}} for f in (result.get("image_findings",[])+result.get("package_findings",[])) if f.get("severity") in ("CRITICAL","HIGH","MEDIUM")]
if result.get("uses_latest_tag"):
steps.append({"action":"pin_image_tag","resource":image,"metadata":{"reason":"latest tag is a security anti-pattern"}})
return steps or [{"action":"no_action_required","resource":image,"metadata":{}}]
def make_receipt(steps):
return hashlib.sha256(json.dumps(steps,sort_keys=True).encode()).hexdigest()