Skip to content

Commit 5aea738

Browse files
galvanadaveqnet
andauthored
Merge pull request from GHSA-g95c-2jgm-hqc6
Co-authored-by: Dave Quinlan <[email protected]>
1 parent c4640a8 commit 5aea738

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

src/fides/api/service/connectors/saas/connector_registry_service.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
replace_dataset_placeholders,
4141
replace_version,
4242
)
43+
from fides.api.util.unsafe_file_util import verify_zip
4344
from fides.config import CONFIG
4445

4546

@@ -181,6 +182,9 @@ def save_template(cls, db: Session, zip_file: ZipFile) -> None:
181182
custom connector template, registers the template, and saves it to the database.
182183
"""
183184

185+
# verify the zip file before we use it
186+
verify_zip(zip_file)
187+
184188
config_contents = None
185189
dataset_contents = None
186190
icon_contents = None
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from typing import Optional
2+
from zipfile import ZipFile
3+
4+
MAX_FILE_SIZE = 16 * 1024 * 1024 # 16 MB
5+
CHUNK_SIZE = 1024
6+
7+
8+
def verify_zip(zip_file: ZipFile, max_file_size: Optional[int] = None) -> None:
9+
"""
10+
Function to safely verify the contents of zipped files. It prevents potential
11+
'zip bomb' attacks by checking the file size of the files in the zip without fully
12+
extracting them. If the size of any file in the zip exceeds the specified
13+
max_file_size, it raises a ValueError. If the max_file_size is not provided,
14+
it uses a default value of 16 MB.
15+
16+
:param zip_file: A ZipFile object to be verified.
17+
:param max_file_size: An optional integer specifying the maximum bytes allowed per file. If not provided, a default value is used.
18+
:raises ValueError: If a file in the zip file exceeds the maximum allowed size
19+
"""
20+
21+
if max_file_size is None:
22+
max_file_size = MAX_FILE_SIZE
23+
24+
for file_info in zip_file.infolist():
25+
file_size = 0
26+
27+
with zip_file.open(file_info) as file:
28+
# wraps the file read in an iterator that stops once no bytes
29+
# are returned or the max file size is reached
30+
for chunk in iter(lambda: file.read(CHUNK_SIZE), b""):
31+
file_size += len(chunk)
32+
33+
if file_size > max_file_size:
34+
raise ValueError("File size exceeds maximum allowed size")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from io import BytesIO
2+
from zipfile import ZipFile
3+
4+
import pytest
5+
6+
from fides.api.util.unsafe_file_util import verify_zip
7+
from tests.ops.test_helpers.saas_test_utils import create_zip_file
8+
9+
10+
class TestVerifyZip:
11+
@pytest.fixture
12+
def zip_file(self) -> BytesIO:
13+
return create_zip_file(
14+
{
15+
"config.yml": "This file isn't that big, but it will be considered suspicious if the max file size is set too low",
16+
}
17+
)
18+
19+
def test_verify_zip(self, zip_file):
20+
verify_zip(ZipFile(zip_file))
21+
22+
def test_verify_zip_with_small_file_size_limit(self, zip_file):
23+
"""We set the max file size to 1 byte, so the zip file should be rejected."""
24+
with pytest.raises(ValueError) as exc:
25+
verify_zip(ZipFile(zip_file), 1)
26+
assert "File size exceeds maximum allowed size" in str(exc.value)

0 commit comments

Comments
 (0)