Skip to content

Commit c5f11a7

Browse files
Merge branch 'release/3.5.25'
2 parents 15a59b0 + ac6b527 commit c5f11a7

File tree

9 files changed

+251
-68
lines changed

9 files changed

+251
-68
lines changed

.github/workflows/build.yml

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,15 @@ jobs:
149149
150150
if [ ! -f "$dockerfile_path" ]; then
151151
echo "Dockerfile not found in $dockerfile_path. Creating one..."
152-
echo "FROM python:3-alpine" > "$dockerfile_path"
153-
echo "RUN apk add --no-cache openssl ca-certificates" >> "$dockerfile_path"
152+
#echo "FROM python:3-alpine" > "$dockerfile_path"
153+
#echo "RUN apk add --no-cache openssl ca-certificates" >> "$dockerfile_path"
154+
echo "FROM python:3-slim" > "$dockerfile_path"
155+
# echo "RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && rm -rf /var/lib/apt/lists/*" >> "$dockerfile_path"
154156
155157
# Check if current worker is among special alpine workers
156158
if echo "$special_alpine_workers" | grep -qw "$matrix_directory"; then
157-
echo "RUN apk add --no-cache file-dev && rm -rf /var/cache/apk/*" >> "$dockerfile_path"
159+
# echo "RUN apk add --no-cache file-dev && rm -rf /var/cache/apk/*" >> "$dockerfile_path"
160+
echo "RUN apt-get update && apt-get install -y --no-install-recommends libmagic1 && rm -rf /var/lib/apt/lists/*" >> "$dockerfile_path"
158161
fi
159162
160163
echo "WORKDIR /worker" >> "$dockerfile_path"
@@ -272,6 +275,16 @@ jobs:
272275
org.opencontainers.image.url=https://thehive-project.org
273276
org.opencontainers.image.version=${{ env.VERSION }}
274277
278+
- name: Scan image for vulnerabilities (Trivy)
279+
uses: aquasecurity/trivy-action@0.32.0
280+
with:
281+
image-ref: ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.IMAGE_TAG }}
282+
format: table
283+
vuln-type: 'os,library'
284+
severity: 'CRITICAL,HIGH'
285+
exit-code: 0
286+
ignore-unfixed: true
287+
275288
- name: Test imports in the container (amd64)
276289
if: ${{ steps.check-rebuild.outputs.rebuild == 'true' && contains(env.PLATFORMS, 'linux/amd64') }}
277290
run: |
@@ -557,13 +570,14 @@ jobs:
557570
558571
if [ ! -f "$dockerfile_path" ]; then
559572
echo "Dockerfile not found in $dockerfile_path. Creating one..."
560-
echo "FROM python:3-alpine" > "$dockerfile_path"
561-
echo "RUN apk add --no-cache openssl ca-certificates" >> "$dockerfile_path"
562-
573+
# echo "FROM python:3-alpine" > "$dockerfile_path"
574+
# echo "RUN apk add --no-cache openssl ca-certificates bind-tools" >> "$dockerfile_path"
575+
echo "FROM python:3-slim" > "$dockerfile_path"
563576
564577
# Check if current worker is among special alpine workers
565578
if echo "$special_alpine_workers" | grep -qw "$matrix_directory"; then
566-
echo "RUN apk add --no-cache file-dev && rm -rf /var/cache/apk/*" >> "$dockerfile_path"
579+
# echo "RUN apk add --no-cache file-dev && rm -rf /var/cache/apk/*" >> "$dockerfile_path"
580+
echo "RUN apt-get update && apt-get install -y --no-install-recommends libmagic1 && rm -rf /var/lib/apt/lists/*" >> "$dockerfile_path"
567581
fi
568582
569583
echo "WORKDIR /worker" >> "$dockerfile_path"
@@ -682,6 +696,16 @@ jobs:
682696
org.opencontainers.image.url=https://thehive-project.org
683697
org.opencontainers.image.version=${{ env.VERSION }}
684698
699+
- name: Scan image for vulnerabilities (Trivy)
700+
uses: aquasecurity/trivy-action@0.32.0
701+
with:
702+
image-ref: ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.IMAGE_TAG }}
703+
format: table
704+
vuln-type: 'os,library'
705+
severity: 'CRITICAL,HIGH'
706+
exit-code: 0
707+
ignore-unfixed: true
708+
685709
- name: Test imports in the container (amd64)
686710
if: ${{ steps.check-rebuild.outputs.rebuild == 'true' && contains(env.PLATFORMS, 'linux/amd64') }}
687711
run: |

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## [3.5.24](https://github.com/TheHive-Project/Cortex-Analyzers/tree/3.5.24) (2025-08-18)
4+
5+
[Full Changelog](https://github.com/TheHive-Project/Cortex-Analyzers/compare/3.5.23...3.5.24)
6+
7+
**Merged pull requests:**
8+
9+
- Elasticsearch Analyzer: Fix deprecated timeout constructor argument [\#1374](https://github.com/TheHive-Project/Cortex-Analyzers/pull/1374) ([bytinbit](https://github.com/bytinbit))
10+
311
## [3.5.23](https://github.com/TheHive-Project/Cortex-Analyzers/tree/3.5.23) (2025-08-12)
412

513
[Full Changelog](https://github.com/TheHive-Project/Cortex-Analyzers/compare/3.5.22...3.5.23)
@@ -104,6 +112,10 @@
104112

105113
[Full Changelog](https://github.com/TheHive-Project/Cortex-Analyzers/compare/3.5.12...3.5.13)
106114

115+
**Closed issues:**
116+
117+
- MISP Analyzer \(misp:2 image\) fails with 'input: null' and 'worker didn't generate output file' on Python 3.13.3 [\#1355](https://github.com/TheHive-Project/Cortex-Analyzers/issues/1355)
118+
107119
**Merged pull requests:**
108120

109121
- Fix analyzer: incompatible ctx.io api \[Malwares\] [\#1350](https://github.com/TheHive-Project/Cortex-Analyzers/pull/1350) ([Ignatella](https://github.com/Ignatella))

analyzers/EmlParser/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
#
1313
#
1414

15-
FROM python:3-slim
15+
FROM python:3-slim-bookworm
1616
WORKDIR /worker
1717
RUN apt update
1818
RUN apt install -y wkhtmltopdf python3-magic
1919
COPY requirements.txt EmlParser/
2020
RUN test ! -e EmlParser/requirements.txt || pip install --no-cache-dir -r EmlParser/requirements.txt
2121
COPY . EmlParser/
22-
ENTRYPOINT ["python", "EmlParser/parse.py"]
22+
ENTRYPOINT ["python", "EmlParser/parse.py"]

analyzers/MalwareBazaar/MalwareBazaar_analyzer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ def run(self):
1717
results = {}
1818
if self.data_type == 'hash':
1919
if len(data) in [32, 40, 64]:
20-
headers = { 'API-KEY': self.api_key }
20+
headers = { 'Auth-Key': self.api_key }
2121
data = {
2222
'query': 'get_info',
2323
'hash': data,
2424
}
2525
results = requests.post(BASEURL, data=data, timeout=15, headers=headers)
2626

27-
if results.status_code == 200:
27+
if 200 <= results.status_code < 300:
2828
results = results.json()
2929
if results['query_status'] in ['http_post_expected', 'illegal_hash', 'no_hash_provided']:
30-
self.error('MalwareBazaar returned error: %s' % results['query_status'])
30+
self.error(f'MalwareBazaar returned error: {results["query_status"]}')
3131
elif results['query_status'] != 'hash_not_found':
3232
results['data'] = results['data'][0]
3333
else:
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{
2+
"name": "DevTools_Echo",
3+
"version": "1.0",
4+
"author": "Fabien Bloume, StrangeBee",
5+
"url": "https://github.com/TheHive-Project/Cortex-Analyzers",
6+
"license": "AGPL-V3",
7+
"description": "Development utility that simply echoes the (available) input received by the analyzer.",
8+
"dataTypeList": [
9+
"ip",
10+
"domain",
11+
"url",
12+
"fqdn",
13+
"mail",
14+
"file",
15+
"hash",
16+
"filename",
17+
"uri_path",
18+
"user-agent",
19+
"mail-subject"
20+
],
21+
"baseConfig": "TestAnalyzer",
22+
"command": "TestAnalyzer/testing.py",
23+
"config": {
24+
"service": "echo"
25+
},
26+
"configurationItems": [
27+
{
28+
"name": "some_string",
29+
"description": "placeholder string",
30+
"type": "string",
31+
"multi": false,
32+
"required": false,
33+
"defaultValue": "some string.."
34+
},
35+
{
36+
"name": "some_list",
37+
"description": "placeholder list",
38+
"type": "string",
39+
"multi": true,
40+
"required": false,
41+
"defaultValue": [
42+
"item1",
43+
"item2",
44+
"item3"
45+
]
46+
},
47+
{
48+
"name": "some_number",
49+
"description": "placeholder number",
50+
"type": "number",
51+
"multi": false,
52+
"required": false,
53+
"defaultValue": 1
54+
},
55+
{
56+
"name": "throw_error",
57+
"description": "throw an error!",
58+
"type": "boolean",
59+
"multi": false,
60+
"required": true,
61+
"defaultValue": false
62+
}
63+
],
64+
"registration_required": false,
65+
"subscription_required": false,
66+
"free_subscription": false,
67+
"serviceHomepage": "None"
68+
}

analyzers/TestAnalyzer/testing.py

Lines changed: 106 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,69 +3,121 @@
33

44
from cortexutils.analyzer import Analyzer
55

6+
67
class TestAnalyzer(Analyzer):
78
def __init__(self):
89
Analyzer.__init__(self)
9-
self.some_string = self.get_param(
10-
"config.some_string", None, "some_string parameter is missing"
11-
)
12-
self.some_list = self.get_param(
13-
"config.some_list", ["item1", "item2", "item3"], "some_list parameter is missing"
14-
)
15-
self.some_number = self.get_param(
16-
"config.some_number", 1, "some_number parameter is missing"
17-
)
10+
self.some_string = self.get_param("config.some_string", None)
11+
self.some_list = self.get_param("config.some_list", ["item1", "item2", "item3"])
12+
self.some_number = self.get_param("config.some_number", 1)
1813
self.throw_error = self.get_param(
1914
"config.throw_error", False, "throw_error parameter is missing"
2015
)
21-
16+
self.service = self.get_param(
17+
"config.service", None, "Service parameter is missing"
18+
)
19+
2220
def run(self):
23-
if self.throw_error:
24-
error_message = "this is an error string: throw_error boolean is set to True in Cortex"
25-
self.error(error_message)
26-
data = self.get_data()
27-
#data = self.get_param("data", None, "Data is missing")
28-
datatype = self.data_type
29-
30-
#result = {"data": data, "dataType": datatype, "arrayExample": ["A", "B", "C"], "tableExample": {"colA": "row A value", "colB": "row B value", "colC": "row C value",}}
31-
32-
# Unicode test data
33-
unicode_test_string = "こんにちは, 你好, 안녕하세요, 😀, 💻, π, ∑, ∞, « Bonjour, comment ça va ? »"
34-
unicode_table_example = {
35-
"colA": "Row A: こんにちは (Hello in Japanese)",
36-
"colB": "Row B: 你好 (Hello in Chinese)",
37-
"colC": "Row C: 😀 (Smiley emoji)",
38-
"colD": "«Row D: Bonjour, comment ça va ? Très bien. » (Hello, how are you? Doing very well. in French)"
39-
}
40-
41-
result = {
42-
"data": data,
43-
"dataType": datatype,
44-
"arrayExample": ["A", "B", "C", "Δ", "Ж", "Ω", "💡"],
45-
"tableExample": unicode_table_example,
46-
"unicodeTest": unicode_test_string
47-
}
48-
49-
self.report(result)
50-
21+
try:
22+
if self.throw_error:
23+
error_message = "this is an error string: throw_error boolean is set to True in Cortex"
24+
self.error(error_message)
25+
data = self.get_data()
26+
# data = self.get_param("data", None, "Data is missing")
27+
datatype = self.data_type
28+
29+
if self.service == "echo":
30+
everything = {
31+
# Observable metadata
32+
# "_id": self.get_param("_id", None), ## Not supported / Not in input
33+
# "_type": self.get_param("_type", None), ## Not supported / Not in input
34+
# "_createdBy": self.get_param("_createdBy", None), ## Not supported / Not in input
35+
# "_updatedBy": self.get_param("_updatedBy", None), ## Not supported / Not in input
36+
# "_createdAt": self.get_param("_createdAt", None), ## Not supported / Not in input
37+
# "_updatedAt": self.get_param("_updatedAt", None), ## Not supported / Not in input
38+
39+
# Core observable
40+
"dataType": self.get_param("dataType", None),
41+
"data": self.get_param("data", None),
42+
43+
# Dates
44+
# "startDate": self.get_param("startDate", None), ## Not supported / Not in input
45+
46+
# TLP / PAP
47+
"tlp": self.get_param("tlp", None),
48+
# "tlpLabel": self.get_param("tlpLabel", None), ## Not supported / Not in input
49+
"pap": self.get_param("pap", None),
50+
# "papLabel": self.get_param("papLabel", None), ## Not supported / Not in input
51+
52+
# Tags / IOC / Sighted
53+
# "tags": self.get_param("tags", None), ## Not supported / Not in input
54+
# "ioc": self.get_param("ioc", None), ## Not supported / Not in input
55+
# "sighted": self.get_param("sighted", None), ## Not supported / Not in input
56+
# "sightedAt": self.get_param("sightedAt", None), ## Not supported / Not in input
57+
# "ignoreSimilarity": self.get_param("ignoreSimilarity", None), ## Not supported / Not in input
58+
59+
# Reports
60+
# "reports": self.get_param("reports", None), ## Not supported / Not in input
61+
62+
# Message
63+
"message": self.get_param("message", None), # Represents case ID!
64+
65+
# Extra data
66+
# "extraData": self.get_param("extraData", None), ## Not supported / Not in input
67+
68+
# File / attachment (if applicable)
69+
"file": self.get_param("file", None), ## Not in input (null unless dataType=="file")
70+
"attachment": self.get_param("attachment", None),## Not supported / Not in input
71+
72+
# Job parameters & analyzer config blocks
73+
"parameters": self.get_param("parameters", {}),
74+
"config": self.get_param("config", {}),
75+
76+
# Proxy (if passed)
77+
"proxy": self.get_param("proxy", {}),
78+
}
79+
result = everything
80+
81+
elif self.service == "testing":
82+
# result = {"data": data, "dataType": datatype, "arrayExample": ["A", "B", "C"], "tableExample": {"colA": "row A value", "colB": "row B value", "colC": "row C value",}}
83+
84+
# Unicode test data
85+
unicode_test_string = "こんにちは, 你好, 안녕하세요, 😀, 💻, π, ∑, ∞, « Bonjour, comment ça va ? »"
86+
unicode_table_example = {
87+
"colA": "Row A: こんにちは (Hello in Japanese)",
88+
"colB": "Row B: 你好 (Hello in Chinese)",
89+
"colC": "Row C: 😀 (Smiley emoji)",
90+
"colD": "«Row D: Bonjour, comment ça va ? Très bien. » (Hello, how are you? Doing very well. in French)",
91+
}
92+
93+
result = {
94+
"data": data,
95+
"dataType": datatype,
96+
"arrayExample": ["A", "B", "C", "Δ", "Ж", "Ω", "💡"],
97+
"tableExample": unicode_table_example,
98+
"unicodeTest": unicode_test_string,
99+
}
100+
101+
self.report(result)
102+
except Exception as e:
103+
self.error(f"Unhandled exception: {e}")
104+
51105
def summary(self, raw):
52106
taxonomies = []
53107
namespace = "testing"
54108
predicate = self.data_type
55109
value = "None"
56-
57-
# safe, info, suspicious, malicious
58-
for level in ["info", "safe", "suspicious", "malicious"]:
59-
taxonomies.append(
60-
self.build_taxonomy(
61-
level, namespace, predicate, value)
62-
)
63-
110+
111+
if self.service == "testing":
112+
# safe, info, suspicious, malicious
113+
for level in ["info", "safe", "suspicious", "malicious"]:
114+
taxonomies.append(
115+
self.build_taxonomy(level, namespace, predicate, value)
116+
)
64117
return {"taxonomies": taxonomies}
65118

66119
def operations(self, raw):
67120
operations = []
68-
operations.append(self.build_operation('AddTagToArtifact', tag="test"))
69121
## For reference only
70122
# case class AddTagToCase(tag: String) extends ActionOperation
71123
# case class AddTagToArtifact(tag: String) extends ActionOperation
@@ -86,16 +138,17 @@ def operations(self, raw):
86138
# tags: Option[Seq[String]]
87139
# ) extends ActionOperation
88140
# case class AssignCase(owner: String) extends ActionOperation
141+
if self.service == "testing":
142+
operations.append(self.build_operation("AddTagToArtifact", tag="test"))
89143
return operations
90144

91145
def artifacts(self, raw):
92146
artifacts = []
93-
data_type = "ip"
94-
value = "8.8.8.8"
95-
extra_args = {
96-
"tags": ["test"]
97-
}
98-
artifacts.append(self.build_artifact(data_type, value, **extra_args))
147+
if self.service == "testing":
148+
data_type = "ip"
149+
value = "8.8.8.8"
150+
extra_args = {"tags": ["test"]}
151+
artifacts.append(self.build_artifact(data_type, value, **extra_args))
99152
return artifacts
100153

101154

0 commit comments

Comments
 (0)