If you use Python’s aiohttp for serving web content, you need to know about CVE-2024-27306. Aiohttp is a popular async web framework, often used for both clients and servers. Between versions before 3.9.4, it contains a vulnerability where attackers can inject JavaScript into index pages generated by aiohttp’s static file handler. This can lead to cross-site scripting (XSS), where malicious scripts run in your users’ browsers.
Let's break down how it works, how to exploit it, and most importantly, how to fix it.
What’s the Vulnerability?
When you configure aiohttp to serve static directories, it can automatically generate an HTML "index" page that lists all files and subfolders. If a directory or filename contains special HTML characters, like <script>, those characters aren’t always properly escaped in some aiohttp versions.
So, if a user can control a filename or directory name—maybe through uploads—an attacker might sneak JavaScript into the generated index page.
Suppose you have a folder public/ served with code like
from aiohttp import web
app = web.Application()
app.router.add_static('/static/', path='public/', show_index=True)
web.run_app(app)
Now, someone uploads a file called <script>alert("XSS")</script>.txt to public/. When someone visits http://yourserver/static/, aiohttp will list all files. But instead of showing a plain filename, it could render as HTML:
<li><a href="/static/<script>alert("XSS")</script>.txt"><script>alert("XSS")</script>.txt</a></li>
But in the vulnerable version, it might fail to escape characters
<li><a href="/static/<script>alert("XSS")</script>.txt"><script>alert("XSS")</script>.txt</a></li>
Now, the browser runs alert("XSS") as soon as someone loads the directory!
Let’s make this clear with a proof-of-concept. Save this Python code as app.py
from aiohttp import web
import os
# Create a test file with an XSS payload in the name
os.makedirs('public', exist_ok=True)
bad_filename = '<script>alert("XSS")</script>.txt'
with open(f'public/{bad_filename}', 'w') as f:
f.write("Hello, world!")
app = web.Application()
app.router.add_static('/static/', path='public/', show_index=True)
print("Running on http://127...1:808/static/";)
web.run_app(app)
Visit http://127...1:808/static/ and see if an alert pops up. On vulnerable versions (before 3.9.4), it might!
Who Is Affected?
- Vulnerable: Anyone running aiohttp versions before 3.9.4 and serving static files with show_index=True directly to users.
- Safe: Users serving static files behind a reverse proxy (like nginx, which does its own file serving), or those who have show_index=False, or those who have upgraded to version 3.9.4 or later.
Official statement from aiohttp maintainers (see security advisory):
> "We have always recommended using a reverse proxy server (e.g. nginx) for serving static files. Users following the recommendation are unaffected. If you are unable to upgrade, disable show_index for static file handlers."
How Bad Is It?
XSS can let attackers read cookies, impersonate users, or redirect visitors. If your app lets people upload files or create folders, and you’re using vulnerable aiohttp settings, you’re at real risk.
How to Fix
Best option: Upgrade.
Run this command
pip install --upgrade 'aiohttp>=3.9.4'
Short-term workaround:
If upgrading isn’t possible, disable directory listings
app.router.add_static('/static/', path='public/', show_index=False)
Or, use a reverse proxy:
Set up nginx or Apache to handle static files and serve index pages (see aiohttp docs), so untrusted content never passes through aiohttp's index generator.
Links
- CVE-2024-27306 at NVD
- aiohttp GitHub Security Advisory
- aiohttp Release Notes
Final Words
If you use aiohttp’s built-in static file server with directory listings, update now. If you use nginx or disable show_index, you’re safe. Don’t ignore XSS bugs—they’re among the most common and dangerous!
Timeline
Published on: 04/18/2024 15:15:29 UTC
Last modified on: 06/20/2024 13:35:26 UTC