Skip to content
Merged

v6.7.0 #3840

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
59ab69d
Ipqs new features (#3678)
RamboV May 15, 2026
628785c
[GSoC 2026] Scaffold chatbot Django app with ChatSession/ChatMessage …
berardifra May 28, 2026
67a4a66
feat(chatbot): add optional Ollama service via docker override + star…
berardifra May 28, 2026
d267502
[GSoC 2026] Add LangChain ReAct agent with job tools and REST endpoin…
berardifra May 29, 2026
661d2e9
[Connectors] Refactor connector testing framework 1 (#3723)
sanjib2006 May 29, 2026
544cb36
feat(chatbot): add endpoint to retrieve a chat session's messages (#3…
berardifra May 29, 2026
af8d583
[GSoC 2026] Add chat message retention policy with configurable TTL (…
berardifra May 30, 2026
d0b19d3
[GSoC 2026] Add investigation LLM tools to the chatbot agent (refs #3…
berardifra May 30, 2026
6c6ba7a
[Connectors] Fix before_run to fail on partial analyer failures when …
sanjib2006 May 30, 2026
d4b8757
fix(analyzers): handle empty results in Netlas (#3734)
Valyrian-Code Jun 4, 2026
b3e464b
feat(chatbot): add get_data_model LLM tool (#3731)
berardifra Jun 5, 2026
79bae0a
[Connectors] Refactor YETI to API v2 payload and auth schemas (#3736)
sanjib2006 Jun 7, 2026
90a3a47
[GSoC 2026] Add analyzer/playbook LLM tools to the chatbot agent (ref…
berardifra Jun 8, 2026
713c81e
Refactor YETI analyzer to match API v2 auth schemas (#3741)
sanjib2006 Jun 8, 2026
0c40d06
[GSoC 2026] Refactor: split chatbot tool serializers/tests into per-t…
berardifra Jun 8, 2026
8f4292c
[GSoC 2026] Add analyze_observable action tool to the chatbot agent (…
berardifra Jun 8, 2026
1531137
[GSoC 2026] Add chatbot WebSocket consumer with token streaming (refs…
berardifra Jun 10, 2026
ee53d60
fix(chatbot): replace string-ReAct agent with native tool calling (#3…
berardifra Jun 10, 2026
22d2958
fix(analyzers): handle empty ASN history in BGPRanking (#3733)
Valyrian-Code Jun 11, 2026
b59bec8
[GSoC 2026] Add chat sessions list with backend titles and unlocked n…
berardifra Jun 12, 2026
a3e1e36
fix(frontend): re-sync package-lock.json with package.json so npm ci …
berardifra Jun 12, 2026
4584506
[GSoC 2026] Proactive chatbot availability (health endpoint + drawer …
berardifra Jun 12, 2026
ead61a9
[GSoC 2026] Inject current-page context into the chatbot agent (refs …
berardifra Jun 12, 2026
1354e19
refactor(chatbot): extract system prompt to dedicated text file with …
berardifra Jun 12, 2026
0429a96
test(misp): migrate to base connector test framework
sanjib2006 Jun 13, 2026
290e49a
Merge pull request #3778 from intelowlproject/gsoc-2026/refactor-conn…
sanjib2006 Jun 13, 2026
4c5994f
[GSoC 2026] Add context-aware quick-action buttons to the chat panel …
berardifra Jun 13, 2026
ecedea5
[GSoC 2026] feat(chatbot): add per-user rate limiting to REST and Web…
berardifra Jun 13, 2026
06408d2
Refactor MISP Connector Exception Handling Closes #3706 (#3781)
sanjib2006 Jun 15, 2026
c51e0fa
[GSoC 2026] Harden chatbot REST + search_jobs (security-review follow…
berardifra Jun 15, 2026
b3017b3
[GSoC 2026] Job tools UI parity: scope with visible_for_user (refs I-…
berardifra Jun 15, 2026
020f197
[GSoC 2026] M-1 guardrail backend: analyze_observable preview-only + …
berardifra Jun 16, 2026
67b784f
[GSoC 2026] M-1 guardrail frontend: analyze Confirm/Cancel card (Refs…
berardifra Jun 18, 2026
e480809
[Connectors] Refactor Testing Framework 3: Migrate OpenCTI tests to B…
sanjib2006 Jun 19, 2026
482b3f7
[GSoC 2026] test(chatbot): E2E chat pipeline + guardrail + ChatPanel …
berardifra Jun 19, 2026
2cf7101
[GSoC 2026] test(chatbot): N+1 query-count guards for the agent tools…
berardifra Jun 19, 2026
b887c9f
[Connectors] Remove Legacy monkeypatches and test files (#3799)
sanjib2006 Jun 22, 2026
bf49541
Add CVE_Exploitability analyzer (CISA KEV + FIRST EPSS) (#3802)
DevamShah Jun 23, 2026
dd0e8c2
test(connectors): fix failing connector tests caused after removing l…
sanjib2006 Jun 24, 2026
8dcb405
[GSoC 2026] chatbot: recover
berardifra Jun 25, 2026
c64af39
fix exiftool failed download (#3812)
mlodic Jun 28, 2026
8a2e069
fix exiftool failed download (#3812)
mlodic Jun 28, 2026
d24e8c6
Add RDAP analyzer (#3760)
thunderstornX Jun 28, 2026
68694fb
[Connectors] Implement health check for connectors (#3811)
sanjib2006 Jun 30, 2026
b494251
Merge branch 'develop' into gsoc-2026/llm-chatbot
berardifra Jun 30, 2026
3f586d3
[GSoC 2026] fix: make --ollama work in test/dev mode. Closes #3829 (#…
berardifra Jun 30, 2026
a356a4c
[GSoC 2026] fix(deps): bump langchain 0.3.25 -> 0.3.30 (fixes GHSA-36…
berardifra Jun 30, 2026
f7d5db0
[GSoC 2026] style: format ChatPanel.jsx with prettier
berardifra Jun 30, 2026
5bd1318
[GSoC 2026] ci: allowlist GHSA-gr75-jv2w-4656 in dependency-review (u…
berardifra Jun 30, 2026
4ce56b1
Merge pull request #3831 from intelowlproject/gsoc-2026/llm-chatbot
mlodic Jul 1, 2026
a5cc647
[GSoC 2026] fix(chatbot): round up rate limiter retry_after (#3836)
berardifra Jul 1, 2026
13ed5d8
test(connectors): remove redundant execution logic from test_subclass…
sanjib2006 Jul 1, 2026
491f03c
Merge pull request #3832 from intelowlproject/gsoc-2026/connectors
mlodic Jul 1, 2026
f30036e
[GSoC 2026] ci: run --ollama on the develop->master build, gate the s…
berardifra Jul 1, 2026
d301de3
build(deps): bump pyelftools from 0.31 to 0.33 in /requirements (#3820)
dependabot[bot] Jul 1, 2026
e95fdb3
build(deps): bump google-cloud-webrisk in /requirements (#3815)
dependabot[bot] Jul 1, 2026
18365d7
build(deps): bump actions/cache from 5 to 6 (#3825)
dependabot[bot] Jul 1, 2026
4ff9d86
build(deps): bump actions/setup-python from 6.2.0 to 6.3.0 (#3826)
dependabot[bot] Jul 1, 2026
a627d26
build(deps): bump library/nginx in /docker (#3803)
dependabot[bot] Jul 1, 2026
3e23e07
Update GoReSym from v3.0.2 to v3.3 (#3665)
github-actions[bot] Jul 1, 2026
08d3458
Update droidlysis from c1645a5 to ce37151 (#3666)
github-actions[bot] Jul 1, 2026
a03b82f
bump and changelog
mlodic Jul 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

[**Upgrade Guide**](https://intelowlproject.github.io/docs/IntelOwl/installation/#update-to-the-most-recent-version)

## [v6.7.0](https://github.com/intelowlproject/IntelOwl/releases/tag/v6.7.0)
We welcome the first working AI-based integration in IntelOwl! :tada:

We invite all the users to test our new awesome Chatbot! :sunglasses: Check the [official doc](https://intelowlproject.github.io/docs/IntelOwl/chatbot/) for more info.

Mainly this release merges all the developments performed by our Google Summer of Code contributors during the last month:
* [Francesco Berardi](https://github.com/berardifra): "Integrating a Self-Deployed LLM Chatbot for Threat Intelligence"
* [Sanjib Behera](https://github.com/sanjib2006): "Integration Ecosystem & Connector Optimization"

## [v6.6.1](https://github.com/intelowlproject/IntelOwl/releases/tag/v6.6.1)
A lot of minor contributions to fix bugs and improve maintenance.

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
fetch-depth: 2

- name: Set up Python
uses: actions/setup-python@v6.2.0
uses: actions/setup-python@v6.3.0
with:
python-version: '3.11'

Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/dependency_review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,11 @@ jobs:
- name: 'Checkout Repository'
uses: actions/checkout@v6.0.2
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4
uses: actions/dependency-review-action@v4
with:
# GHSA-gr75-jv2w-4656: LangChain path traversal in file-search middleware/loaders.
# Patched only in langchain 1.3.9 (breaking major upgrade). The chatbot uses no
# document loaders, file-search middleware, or hub prompt pulls (only langchain.agents,
# langchain_core.*, langchain_ollama), so the vulnerable code paths are unreachable.
# Accepted until the planned langchain 1.x migration. Approved by @mlodic.
allow-ghsas: GHSA-gr75-jv2w-4656
15 changes: 10 additions & 5 deletions .github/workflows/pull_request_automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
uses: actions/checkout@v6.0.2

- name: Set up Python
uses: actions/setup-python@v6.2.0
uses: actions/setup-python@v6.3.0
with:
python-version: 3.11

Expand Down Expand Up @@ -87,18 +87,23 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}

- name: Startup script launch (Slow)
if: contains(github.base_ref, 'master')
# Only the develop -> master release PR runs the full build: extra analyzers plus the
# chatbot stack (--ollama), which smoke-tests the ollama + celery_worker_chatbot topology
# on the :ci image. Kept off every other PR because the model pull is heavy.
if: github.base_ref == 'master' && github.head_ref == 'develop'
run: |
cp docker/env_file_integrations_template docker/env_file_integrations
./start ci up --malware_tools_analyzers --phishing_analyzers -- --build -d
./start ci up --malware_tools_analyzers --phishing_analyzers --ollama -- --build -d
env:
DOCKER_BUILDKIT: 1
BUILDKIT_PROGRESS: "plain"
STAGE: "ci"
REPO_DOWNLOADER_ENABLED: false

- name: Startup script launch (Fast)
if: "!contains(github.base_ref, 'master')"
# Exact complement of the Slow step so every other PR (incl. a non-develop head into
# master) still gets a container up for the test steps below.
if: ${{ !(github.base_ref == 'master' && github.head_ref == 'develop') }}
run: |
./start ci up -- --build -d
env:
Expand Down Expand Up @@ -137,7 +142,7 @@ jobs:
with:
node-version: 18
- name: Cache node modules
uses: actions/cache@v5
uses: actions/cache@v6
with:
path: ~/.npm
key: npm-build-${{ hashFiles('frontend/package-lock.json') }}
Expand Down
54 changes: 54 additions & 0 deletions api_app/analyzers_manager/file_analyzers/ipqsfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# This file is a part of IntelOwl https://github.com/intelowlproject/IntelOwl
# See the file 'LICENSE' for copying permission.

"""IPQualityScore file analyzer.

Provides `IPQSFileScan`, a file-scanning analyzer that uploads files to
IPQualityScore for malware detection and polls for results.
"""

import logging

from api_app.analyzers_manager.classes import FileAnalyzer
from api_app.mixins import IPQualityScoreMixin

logger = logging.getLogger(__name__)


class IPQSFileScan(FileAnalyzer, IPQualityScoreMixin):
"""
Scan a binary file using IPQualityScore malware detection service.
"""

@classmethod
def update(cls):
pass

def run(self):
binary = self.read_file_bytes()
files = {"files": (self.filename, binary)}
# lookup endpoint check for cached result
lookup_result = self._make_request(
self.lookup_endpoint,
method="POST",
_api_key=self._ipqs_api_key,
files=files,
)
if lookup_result.get("status", False) == "cached":
lookup_result.pop("update_url", None)
return lookup_result
# sending file to ipqs for scan
scan_result = self._make_request(
self.scan_endpoint,
method="POST",
_api_key=self._ipqs_api_key,
files=files,
)
# waiting for scan result with help of request id
result = self._poll_for_report(
endpoint=self.postback_endpoint,
_api_key=self._ipqs_api_key,
request_id=scan_result.get("request_id"),
)
result.pop("update_url", None)
return result
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
from django.db import migrations
from django.db.models.fields.related_descriptors import (
ForwardManyToOneDescriptor,
ForwardOneToOneDescriptor,
ManyToManyDescriptor,
ReverseManyToOneDescriptor,
ReverseOneToOneDescriptor,
)

plugin = {
"python_module": {
"health_check_schedule": None,
"update_schedule": None,
"module": "ipqsfile.IPQSFileScan",
"base_path": "api_app.analyzers_manager.file_analyzers",
},
"name": "IPQS_Malware_File_Scanner",
"description": "Scan files for malware, viruses, and malicious payloads in real-time using [IPQualityScore](https://www.ipqualityscore.com/)'s advanced file scanning engine.",
"disabled": False,
"soft_time_limit": 140,
"routing_key": "default",
"health_check_status": True,
"type": "file",
"docker_based": False,
"maximum_tlp": "AMBER",
"observable_supported": [],
"supported_filetypes": [
"application/w-script-file",
"application/javascript",
"application/x-javascript",
"text/javascript",
"application/x-vbscript",
"text/x-ms-iqy",
"application/vnd.android.package-archive",
"application/x-dex",
"application/onenote",
"application/zip",
"multipart/x-zip",
"application/java-archive",
"text/rtf",
"application/rtf",
"application/x-sharedlib",
"application/vnd.microsoft.portable-executable",
"application/x-elf",
"application/octet-stream",
"application/vnd.tcpdump.pcap",
"application/pdf",
"text/html",
"application/x-mspublisher",
"application/vnd.ms-excel.addin.macroEnabled",
"application/vnd.ms-excel.sheet.macroEnabled.12",
"application/vnd.ms-excel",
"application/excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/xml",
"text/xml",
"application/encrypted",
"text/plain",
"text/csv",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-powerpoint",
"application/vnd.ms-office",
"application/x-binary",
"application/x-macbinary",
"application/mac-binary",
"application/x-mach-binary",
"application/x-zip-compressed",
"application/x-compressed",
"application/vnd.ms-outlook",
"message/rfc822",
"application/pkcs7-signature",
"application/x-pkcs7-signature",
"multipart/mixed",
"text/x-shellscript",
"application/x-chrome-extension",
"application/json",
"application/x-executable",
"text/x-java",
"text/x-kotlin",
"text/x-swift",
"text/x-objective-c",
"application/x-ms-shortcut",
"application/gzip",
],
"run_hash": False,
"run_hash_type": "",
"not_supported_filetypes": [],
"mapping_data_model": {},
"model": "analyzers_manager.AnalyzerConfig",
}

params = [
{
"python_module": {
"module": "ipqsfile.IPQSFileScan",
"base_path": "api_app.analyzers_manager.file_analyzers",
},
"name": "ipqs_api_key",
"type": "str",
"description": "Please provide the IPQS API key.",
"is_secret": True,
"required": True,
},
{
"python_module": {
"module": "ipqsfile.IPQSFileScan",
"base_path": "api_app.analyzers_manager.file_analyzers",
},
"name": "polling_interval",
"type": "int",
"description": "Recommended polling interval: 10 seconds.",
"is_secret": False,
"required": True,
},
{
"python_module": {
"module": "ipqsfile.IPQSFileScan",
"base_path": "api_app.analyzers_manager.file_analyzers",
},
"name": "max_retries",
"type": "int",
"description": "Recommended max retries: 8.",
"is_secret": False,
"required": True,
},
]

values = []


def _get_real_obj(Model, field, value):
def _get_obj(Model, other_model, value):
if isinstance(value, dict):
real_vals = {}
for key, real_val in value.items():
real_vals[key] = _get_real_obj(other_model, key, real_val)
value = other_model.objects.get_or_create(**real_vals)[0]
# it is just the primary key serialized
else:
if isinstance(value, int):
if Model.__name__ == "PluginConfig":
value = other_model.objects.get(name=plugin["name"])
else:
value = other_model.objects.get(pk=value)
else:
value = other_model.objects.get(name=value)
return value

if (
type(getattr(Model, field))
in [
ForwardManyToOneDescriptor,
ReverseManyToOneDescriptor,
ReverseOneToOneDescriptor,
ForwardOneToOneDescriptor,
]
and value
):
other_model = getattr(Model, field).get_queryset().model
value = _get_obj(Model, other_model, value)
elif type(getattr(Model, field)) in [ManyToManyDescriptor] and value:
other_model = getattr(Model, field).rel.model
value = [_get_obj(Model, other_model, val) for val in value]
return value


def _create_object(Model, data):
mtm, no_mtm = {}, {}
for field, value in data.items():
value = _get_real_obj(Model, field, value)
if type(getattr(Model, field)) is ManyToManyDescriptor:
mtm[field] = value
else:
no_mtm[field] = value
try:
o = Model.objects.get(**no_mtm)
except Model.DoesNotExist:
o = Model(**no_mtm)
o.full_clean()
o.save()
for field, value in mtm.items():
attribute = getattr(o, field)
if value is not None:
attribute.set(value)
return False
return True


def migrate(apps, schema_editor):
Parameter = apps.get_model("api_app", "Parameter")
PluginConfig = apps.get_model("api_app", "PluginConfig")
python_path = plugin.pop("model")
Model = apps.get_model(*python_path.split("."))
if not Model.objects.filter(name=plugin["name"]).exists():
exists = _create_object(Model, plugin)
if not exists:
for param in params:
_create_object(Parameter, param)
for value in values:
_create_object(PluginConfig, value)


def reverse_migrate(apps, schema_editor):
python_path = plugin.pop("model")
Model = apps.get_model(*python_path.split("."))
Model.objects.get(name=plugin["name"]).delete()


class Migration(migrations.Migration):
atomic = False
dependencies = [
("api_app", "0073_alter_updatecheckstatus_last_checked_at_and_more"),
("analyzers_manager", "0190_remove_greynoise_labs_analyzer"),
]

operations = [migrations.RunPython(migrate, reverse_migrate)]
Loading
Loading