Information disclosure via filesystem existence oracle in web_main.py catch-all route
Maintainer thường phản hồi trong vòng 1 ngày
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 78/100
Hướng nghiên cứu
Bắt đầu tại application/web/web_main.py:747-753 và kiểm tra route index catch-all, sau đó tái hiện các phản hồi khác nhau bằng Flask test client với các path tồn tại và không tồn tại bên ngoài thư mục static. Thêm một regression test bao quát các trường hợp đó và xác minh rằng cả hai đều được phân giải nhất quán thành phản hồi dự kiến mà không để lộ sự tồn tại trong filesystem.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
@northdpole as discussed in #project-cre.
Summary
The catch-all route that serves the React app answers differently depending on whether a path exists on the server filesystem, so an unauthenticated caller can test for arbitrary paths outside the static directory. File contents do not leak; existence does.
Where
application/web/web_main.py:747-753 (on fbacf559):
@app.route("/", defaults={"path": ""})
@app.route("/<path:path>")
def index(path: str) -> Any:
if path != "" and os.path.exists(os.path.join(app.static_folder, path)):
return send_from_directory(app.static_folder, path)
else:
return send_from_directory(app.static_folder, "index.html")
Why it happens
Two functions decide what is in bounds and they disagree.
os.path.join applies no containment check, and Flask's <path:path> converter passes .. through, so the guard resolves paths outside the static root and os.path.exists answers about them truthfully.
send_from_directory does check, through Werkzeug's safe_join, and refuses anything that escapes, raising 404.
The read is therefore blocked. But the two branches return different responses, and that difference is the leak: an existing path takes the first branch and 404s, a missing one falls through and serves index.html with 200.
Reproduction
Flask 3.1.3, Werkzeug 3.1.8, route copied verbatim into a test client:
GET /../../../../etc/passwd 404 207 bytes (exists)
GET /../../../../etc/definitely-not-here 200 16 bytes (does not exist)
GET /../../../../etc/shadow 404 207 bytes (exists, unreadable)
GET /../../../../root 404 207 bytes (directory, exists)
GET /../../../../home/nonexistentuser 200 16 bytes (does not exist)
404 means the path exists, 200 means it does not. It reports existence for files the process cannot read, and for directories.
Impact
Low. No file contents are disclosed and there is no read primitive; safe_join holds. What leaks is filesystem structure, to an unauthenticated remote caller: host fingerprinting, which packages are installed, whether particular users, config files or deployment paths exist. Roughly CWE-204, observable response discrepancy, reached through a path-traversal-shaped input.
Suggested fix
Have both branches use the same containment rule:
from werkzeug.security import safe_join
@app.route("/", defaults={"path": ""})
@app.route("/<path:path>")
def index(path: str) -> Any:
if path:
full = safe_join(app.static_folder, path)
if full is not None and os.path.exists(full):
return send_from_directory(app.static_folder, path)
return send_from_directory(app.static_folder, "index.html")
Happy to open a PR with this and a regression test if useful.
- Ngôn ngữ chính
- Python
- Star
- 210
- Fork
- 167
- Merge trung bình
- 4 ngày 12 giờ
- Pull request đã merge (30 ngày)
- 28
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Có Dockerfile hoặc tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của OWASP/OpenCRE
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
OWASP/OpenCRE#1215 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Map Analysis continues polling after a background job failsCó thể đã có người làm @amantebriwal4321 đã nhận 4 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
OWASP/OpenCRE#1211 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
OSCAL Compass adopterĐang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 66/100
Maintainer thường phản hồi trong vòng 1 ngày
-
MCP tools return "Internal MCP tool error." when OpenCRE is unreachable or times outCó thể đã có người làm @ShaanGS đã nhận 23 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
OWASP/OpenCRE#1163 · 5 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
find_node_by_name endpoint does not enforce MAX_ITEMS_PER_PAGE, allowing unbounded pagination queries`Có thể đã có người làm @Jeffy123-zhu đã nhận 27 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
OWASP/OpenCRE#1149 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của OWASP/OpenCRE
Issue tương tự
-
SslLibrary crashes with unhandled OSError: port/proto not found on non-standard SSL portsCó thể đã có người làm @himanchalkaushale đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
OWASP/Nettacker#1884 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
A-connection-core C-enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
aws-samples/sample-per-model-bedrock#869 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Spec: say that included_antigen_sources gates LENS labels; do not merge it into antigen kindsĐang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
fzn0x/watchtower#17 ·