CVE-2026-44364
Description
MISP modules are autonomous modules that can be used to extend MISP for new services. In 3.0.7 and earlier, a Cross-Site Request Forgery vulnerability in the MISP Modules website allowed an attacker to cause an authenticated user to submit unintended requests to the home endpoint. The vulnerability was due to the home blueprint being exempted from CSRF protection. This could allow modification of session query data in the context of the authenticated user. The issue was fixed by enabling CSRF protection for the affected blueprint and hardening query parsing.
Patches
152cda9caa003fix: [security] csrf in website, and others in modules
5 files changed · +43 −8
misp_modules/modules/expansion/html_to_markdown.py+38 −2 modified@@ -1,6 +1,9 @@ import json +import socket import requests +import ipaddress +from urllib.parse import urlparse from bs4 import BeautifulSoup from markdownify import markdownify @@ -24,11 +27,44 @@ } + +BLOCKED_RANGES = [ + ipaddress.ip_network("127.0.0.0/8"), + ipaddress.ip_network("10.0.0.0/8"), + ipaddress.ip_network("172.16.0.0/12"), + ipaddress.ip_network("192.168.0.0/16"), + ipaddress.ip_network("169.254.0.0/16"), + ipaddress.ip_network("::1/128"), +] + +def _is_ip_blocked(ip_str: str) -> bool: + ip = ipaddress.ip_address(ip_str) + return any(ip in net for net in BLOCKED_RANGES) + + +def _hostname_resolves_to_blocked_ip(hostname: str) -> bool: + try: + resolved = socket.getaddrinfo(hostname, None) + return any(_is_ip_blocked(info[4][0]) for info in resolved) + except socket.gaierror: + return True + + +def is_safe_url(url: str) -> bool: + parsed = urlparse(url) + if parsed.scheme not in ("http", "https"): + return False + try: + return not _is_ip_blocked(parsed.hostname) + except ValueError: + return not _hostname_resolves_to_blocked_ip(parsed.hostname) + def fetchHTML(url): - r = requests.get(url) + if not is_safe_url(url): + raise ValueError(f"Blocked URL: {url}") + r = requests.get(url, timeout=10) return r.text - def stripUselessTags(html): soup = BeautifulSoup(html, "html.parser") toRemove = ["script", "head", "header", "footer", "meta", "link"]
misp_modules/modules/expansion/jinja_template_rendering.py+3 −1 modified@@ -1,6 +1,7 @@ #!/usr/bin/env python\ import json +import logging from jinja2.sandbox import SandboxedEnvironment @@ -41,7 +42,8 @@ def handler(q=False): templateData = data.get("data", {}) try: rendered = renderTemplate(templateData, template) - except TypeError: + except Exception as e: + logging.warning("Template render failed: %s", type(e).__name__) rendered = "" r = {"results": [{"types": mispattributes["output"], "values": [rendered]}]}
misp_modules/modules/expansion/qrcode.py+1 −2 modified@@ -100,8 +100,7 @@ def fetch_url_image(target_url): target_url, headers=headers, timeout=TIMEOUT_SECONDS, - stream=True, - verify=False + stream=True ) as response: # nosec response.raise_for_status()
website/app/home.py+1 −2 modified@@ -1,4 +1,3 @@ -import ast import json from flask import Blueprint, jsonify, render_template, request @@ -23,7 +22,7 @@ def home(): sess["admin_user"] = bool(admin_user_active()) if "query" in request.args: - sess["query"] = ast.literal_eval(request.args.get("query")) + sess["query"] = json.loads(request.args.get("query")) if "query" in request.form: sess["query"] = json.loads(request.form.get("query")) return render_template("home.html")
website/app/__init__.py+0 −1 modified@@ -58,7 +58,6 @@ def create_app(): app.register_blueprint(history_blueprint, url_prefix="/") app.register_blueprint(account_blueprint, url_prefix="/") app.register_blueprint(external_tools_blueprint, url_prefix="/") - csrf.exempt(home_blueprint) # Register 404 error handler @app.errorhandler(404)
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.