Skip to content

Commit

Permalink
Merge branch 'main' into release-v1.0.15
Browse files Browse the repository at this point in the history
  • Loading branch information
Wout Feys committed Nov 18, 2024
2 parents 9424baf + d8437c1 commit 87522af
Show file tree
Hide file tree
Showing 17 changed files with 49 additions and 50 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Zen protects your Python apps by preventing user input containing dangerous stri
Zen will autonomously protect your Python applications from the inside against:

* 🛡️ [NoSQL injection attacks](https://www.aikido.dev/blog/web-application-security-vulnerabilities)
* 🛡️ [SQL injection attacks]([https://www.aikido.dev/blog/web-application-security-vulnerabilities](https://owasp.org/www-community/attacks/SQL_Injection))
* 🛡️ [SQL injection attacks](https://www.aikido.dev/blog/the-state-of-sql-injections)
* 🛡️ [Command injection attacks](https://owasp.org/www-community/attacks/Command_Injection)
* 🛡️ [Path traversal attacks](https://owasp.org/www-community/attacks/Path_Traversal)
* 🛡️ [Server-side request forgery (SSRF)](./docs/ssrf.md)
Expand Down
29 changes: 16 additions & 13 deletions aikido_zen/sinks/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,24 @@
"""

from pathlib import PurePath
import copy
import aikido_zen.importhook as importhook
import aikido_zen.vulnerabilities as vulns


def aikido_open_decorator(func):
"""Decorator for open(...)"""

def wrapper(*args, **kwargs):
# args[0] is thefunc_name filename
if len(args) > 0 and isinstance(args[0], (str, bytes, PurePath)):
vulns.run_vulnerability_scan(
kind="path_traversal", op="builtins.open", args=(args[0],)
)
return func(*args, **kwargs)

return wrapper


@importhook.on_import("builtins")
def on_builtins_import(builtins):
"""
Expand All @@ -17,17 +30,7 @@ def on_builtins_import(builtins):
"""
modified_builtins = importhook.copy_module(builtins)

former_open = copy.deepcopy(builtins.open)

def aikido_new_open(*args, **kwargs):
# args[0] is the filename
if len(args) > 0 and isinstance(args[0], (str, bytes, PurePath)):
vulns.run_vulnerability_scan(
kind="path_traversal", op="builtins.open", args=(args[0],)
)
return former_open(*args, **kwargs)

# pylint: disable=no-member
setattr(builtins, "open", aikido_new_open)
setattr(modified_builtins, "open", aikido_new_open)
setattr(builtins, "open", aikido_open_decorator(builtins.open))
setattr(modified_builtins, "open", aikido_open_decorator(builtins.open))
return modified_builtins
11 changes: 2 additions & 9 deletions aikido_zen/sinks/os_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Sink module for `os`, wrapping os.system
"""

import copy
import aikido_zen.importhook as importhook
import aikido_zen.vulnerabilities as vulns

Expand All @@ -19,18 +18,12 @@ def on_os_import(os):
"""
modified_os = importhook.copy_module(os)

former_system_func = copy.deepcopy(os.system)

def aikido_new_system(
command, *args, former_system_func=former_system_func, **kwargs
):
def aikido_new_system(command, *args, **kwargs):
if isinstance(command, str):
vulns.run_vulnerability_scan(
kind="shell_injection", op="os.system", args=(command,)
)
return former_system_func(command, *args, **kwargs)
return os.system(command, *args, **kwargs)

setattr(os, "system", aikido_new_system)
setattr(modified_os, "system", aikido_new_system)

return modified_os
4 changes: 2 additions & 2 deletions aikido_zen/sinks/psycopg2.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def execute(self, *args, **kwargs):
)
if former_cursor_factory and hasattr(former_cursor_factory, "execute"):
return former_cursor_factory.execute(self, *args, **kwargs)
return super().execute(*args, **kwargs)
return ext.cursor.execute(self, *args, **kwargs)

def executemany(self, *args, **kwargs):
"""Aikido's wrapped executemany function"""
Expand All @@ -37,7 +37,7 @@ def executemany(self, *args, **kwargs):
)
if former_cursor_factory and hasattr(former_cursor_factory, "executemany"):
return former_cursor_factory.executemany(self, *args, **kwargs)
return super().executemany(*args, **kwargs)
return ext.cursor.executemany(self, *args, **kwargs)

return AikidoWrappedCursor

Expand Down
14 changes: 5 additions & 9 deletions aikido_zen/sinks/shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,22 @@
# shutil.copy2(src, dst, *, **) => builtins.open


def generate_aikido_function(op, former_func):
def generate_aikido_function(aik_op, func):
"""
Returns a generated aikido function given an operation
and the previous function
"""

def aikido_new_func(
src, dst, *args, aik_op=op, aik_former_func=former_func, **kwargs
):
def wrapper(src, dst, *args, **kwargs):
kind = "path_traversal"
op = f"shutil.{aik_op}"
if src:
vulns.run_vulnerability_scan(kind, op, args=(src,))
if dst:
vulns.run_vulnerability_scan(kind, op, args=(dst,))
return former_func(src, dst, *args, **kwargs)
return func(src, dst, *args, **kwargs)

return aikido_new_func
return wrapper


@importhook.on_import("shutil")
Expand All @@ -48,9 +46,7 @@ def on_shutil_import(shutil):
modified_shutil = importhook.copy_module(shutil)
for op in SHUTIL_SRC_DST_FUNCTIONS:
# Wrap shutil. functions
former_func = copy.deepcopy(getattr(shutil, op))
aikido_new_func = generate_aikido_function(op, former_func)
setattr(shutil, op, aikido_new_func)
aikido_new_func = generate_aikido_function(op, getattr(shutil, op))
setattr(modified_shutil, op, aikido_new_func)

return modified_shutil
9 changes: 5 additions & 4 deletions aikido_zen/sinks/tests/shutil_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import pytest
from unittest.mock import patch
import aikido_zen.sinks.builtins
import aikido_zen.sinks.shutil
import aikido_zen

aikido_zen.protect("daemon_disabled")


kind = "path_traversal"
Expand Down Expand Up @@ -134,7 +135,7 @@ def test_shutil_copy():
op = "builtins.open"
args1 = ("Makefile",)
args2 = ("test2",)
assert len(mock_run_vulnerability_scan.call_args_list) == 5
assert len(mock_run_vulnerability_scan.call_args_list) == 3
call_1 = mock_run_vulnerability_scan.call_args_list[0]
call_2 = mock_run_vulnerability_scan.call_args_list[1]

Expand All @@ -154,7 +155,7 @@ def test_shutil_copy2():
op = "builtins.open"
args1 = ("Makefile",)
args2 = ("test2",)
assert len(mock_run_vulnerability_scan.call_args_list) == 5
assert len(mock_run_vulnerability_scan.call_args_list) == 3
call_1 = mock_run_vulnerability_scan.call_args_list[0]
call_2 = mock_run_vulnerability_scan.call_args_list[1]

Expand Down
5 changes: 3 additions & 2 deletions end2end/server/check_events_from_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ def validate_started_event(event, stack, dry_mode=False, serverless=False, os_na
assert event["agent"]["os"]["name"] == os_name
assert event["agent"]["platform"]["name"] == platform
assert event["agent"]["serverless"] == serverless
if stack is not None:
assert set(event["agent"]["stack"]) == set(stack)
# # Check for packages is disabled until we start using them in core :
# if stack is not None:
# assert set(event["agent"]["stack"]) == set(stack)

def validate_heartbeat(event, routes, req_stats):
assert event["type"] == "heartbeat"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: "3"
services:
backend_firewall_disabled:
image: sample_django_mysql_gunicorn
command: sh -c "python manage.py migrate && gunicorn -c gunicorn_config.py --workers 4 --threads 2 --log-level debug --access-logfile '-' --error-logfile '-' --bind 0.0.0.0:8000 sample-django-mysql-gunicorn-app.wsgi"
command: sh -c "python manage.py migrate && ddtrace-run gunicorn -c gunicorn_config.py --workers 4 --threads 2 --log-level debug --access-logfile '-' --error-logfile '-' --bind 0.0.0.0:8000 sample-django-mysql-gunicorn-app.wsgi"
restart: always
volumes:
- .:/app
Expand Down
2 changes: 1 addition & 1 deletion sample-apps/django-mysql-gunicorn/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ services:
context: ./../../
dockerfile: ./sample-apps/django-mysql-gunicorn/Dockerfile
container_name: django_mysql_gunicorn_backend
command: sh -c "python manage.py migrate && gunicorn -c gunicorn_config.py --workers 4 --threads 2 --log-level debug --access-logfile '-' --error-logfile '-' --bind 0.0.0.0:8000 sample-django-mysql-gunicorn-app.wsgi"
command: sh -c "python manage.py migrate && ddtrace-run gunicorn -c gunicorn_config.py --workers 4 --threads 2 --log-level debug --access-logfile '-' --error-logfile '-' --bind 0.0.0.0:8000 sample-django-mysql-gunicorn-app.wsgi"
restart: always
volumes:
- .:/app
Expand Down
1 change: 1 addition & 0 deletions sample-apps/django-mysql-gunicorn/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ mysqlclient
python-decouple
cryptography
gunicorn
ddtrace
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: "3"
services:
backend_firewall_disabled:
image: sample_django_postgres_gunicorn
command: sh -c "python manage.py migrate && gunicorn -c gunicorn_config.py --workers 4 --threads 2 --log-level debug --access-logfile '-' --error-logfile '-' --bind 0.0.0.0:8000 sample-django-postgres-gunicorn-app.wsgi"
command: sh -c "python manage.py migrate && ddtrace-run gunicorn -c gunicorn_config.py --workers 4 --threads 2 --log-level debug --access-logfile '-' --error-logfile '-' --bind 0.0.0.0:8000 sample-django-postgres-gunicorn-app.wsgi"
restart: always
volumes:
- .:/app
Expand Down
2 changes: 1 addition & 1 deletion sample-apps/django-postgres-gunicorn/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ services:
context: ./../../
dockerfile: ./sample-apps/django-postgres-gunicorn/Dockerfile
container_name: django_postgres_gunicorn_backend
command: sh -c "python manage.py migrate && gunicorn -c gunicorn_config.py --workers 4 --threads 2 --log-level debug --access-logfile '-' --error-logfile '-' --bind 0.0.0.0:8000 sample-django-postgres-gunicorn-app.wsgi"
command: sh -c "python manage.py migrate && ddtrace-run gunicorn -c gunicorn_config.py --workers 4 --threads 2 --log-level debug --access-logfile '-' --error-logfile '-' --bind 0.0.0.0:8000 sample-django-postgres-gunicorn-app.wsgi"
restart: always
volumes:
- .:/app
Expand Down
1 change: 1 addition & 0 deletions sample-apps/django-postgres-gunicorn/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ python-decouple
cryptography
psycopg2-binary==2.9.9
gunicorn==20.1.0
ddtrace
2 changes: 1 addition & 1 deletion sample-apps/flask-mongo/docker-compose.benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: "3"
services:
backend_firewall_disabled:
image: sample_flask_mongo
command: sh -c "flask --app app run --debug --host=0.0.0.0"
command: sh -c "ddtrace-run flask --app app run --debug --host=0.0.0.0"
restart: always
volumes:
- .:/app
Expand Down
2 changes: 1 addition & 1 deletion sample-apps/flask-mongo/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ services:
context: ./../../
dockerfile: ./sample-apps/flask-mongo/Dockerfile
container_name: flask_mongo_backend
command: sh -c "flask --app app run --debug --host=0.0.0.0"
command: sh -c "ddtrace-run flask --app app run --debug --host=0.0.0.0"
restart: always
volumes:
- .:/app
Expand Down
1 change: 1 addition & 0 deletions sample-apps/flask-mongo/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
flask==2.3.3
Flask-PyMongo
cryptography
ddtrace
10 changes: 6 additions & 4 deletions sample-apps/quart-postgres-uvicorn/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
quart
asyncpg
cryptography
uvicorn
quart==0.17.0
asyncpg==0.27.0
cryptography==39.0.1
uvicorn==0.22.0
Flask==2.3.0
Werkzeug==2.3.0

0 comments on commit 87522af

Please sign in to comment.