Unauthenticated source code and secret disclosure via unrestricted app-directory static serving
What went wrong?
reported on 2 June 2026 https://github.com/Avaiga/taipy/security/advisories/GHSA-jvfw-r45j-mxmx - no response:
Summary
Taipy's default HTTP handler serves any file that exists in the application script's directory when a request path matches the filename. There is no extension or filename deny list. An unauthenticated remote attacker can retrieve the application's Python source files (.py), environment files (.env), configuration files, private keys, and any other file co-located with the app script by simply requesting them by name. The only protection mechanism -- a .taipyignore file -- is not created by default and is completely undocumented, so virtually all production deployments are affected.
Details
The default route handler in _FlaskServer._get_default_handler (taipy/gui/servers/flask/server.py, lines 195-213 in HEAD; lines 220-237 in 4.0.3 server.py) contains two fallback file-serving blocks. The first falls back to the directory of the main application script:
if (
hasattr(__main__, "__file__")
and (
file_path := str(
os.path.normpath((base_path := os.path.dirname(__main__.__file__) + os.path.sep) + path)
)
).startswith(base_path)
and os.path.isfile(file_path)
and not self._is_ignored(file_path)
):
return send_from_directory(base_path, path)The second falls back to _gui._root_dir (the same directory in standard deployments):
if (
(file_path := str(os.path.normpath((base_path := self._gui._root_dir + os.path.sep) + path))).startswith(base_path)
and os.path.isfile(file_path)
and not self._is_ignored(file_path)
):
return send_from_directory(base_path, path)The intent is to allow app authors to reference local CSS, images, and data files in their pages without configuring an explicit path mapping. However, there is no file extension or name filter. The only exclusion mechanism is _is_ignored, which reads a .taipyignore gitignore-format file. If no such file exists (the default in all cases except when using the taipy create SDM template, which generates an empty .taipyignore), _is_ignored always returns False.
A path traversal through the URL is not possible because Werkzeug normalizes .. sequences before the path reaches the route handler. However, any file that exists in the app directory is directly accessible by its filename.
Files typically co-located with a Taipy app script and exposed by this behavior:
app.py/main.py-- application source code with database queries, API keys embedded in source, business logic.env-- environment variables includingDATABASE_URL,SECRET_KEY,AWS_ACCESS_KEY_ID,API_TOKEN, etc.config.py/settings.py-- additional configuration with credentials*.pem,*.key-- TLS certificates and private keysrequirements.txt,Pipfile,pyproject.toml-- dependency manifests (useful for supply-chain reconnaissance)
Verified against taipy-gui 4.0.3 (installed) and commit 5bcb574 (develop/4.2.0.dev9).
PoC
Prerequisites: A Taipy application running with any sensitive file present in the same directory as the main script.
Start a Taipy application (
gui.run(host="0.0.0.0", port=9720)).Create a
.envfile in the app directory with secrets:DATABASE_URL=postgresql://user:password123@db:5432/app SECRET_KEY=mysecretkey AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLEAs an unauthenticated remote user, request the file:
GET /.env HTTP/1.1 Host: victim.company.com:9720Response:
HTTP/1.1 200 OK Content-Disposition: inline; filename=.env Content-Type: application/octet-stream Content-Length: 117 DATABASE_URL=postgresql://user:password123@db:5432/app SECRET_KEY=mysecretkey AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLESimilarly, source code is exposed:
GET /app.py HTTP/1.1 Host: victim.company.com:9720Returns the full Python source code of the application.
One-line curl proof:
# Returns the app's .env file contents
curl http://victim.company.com:9720/.env
# Returns the app's main Python source file
curl http://victim.company.com:9720/main.pyImpact
An unauthenticated attacker with network access to the Taipy application can read any file in the application's working directory. In typical deployments this includes the full application source code, environment files containing database credentials and API keys, private keys, and configuration files. The impact is direct credential compromise, data exfiltration, and full application takeover via the exposed secrets.
Taipy Version
4.0.3
Additional Context (Optional)
Code of Conduct
- I have checked the existing issues to avoid duplicates.
- I am willing to work on this issue (optional)
✅ Acceptance Criteria
- A reproducible unit test is added.
- Code coverage is at least 90%.
- The bug reporter validated the fix.
- Relevant documentation updates or an issue created in
Source: Avaiga/taipy