T3MP3ST public launch build

This commit is contained in:
t3mp3st contributors committed 2026-07-03 10:57:20 -04:00
1 parent 972247b881
commit 184c7d4e59
1589 files changed
+57150 -506

No files matched your search

@@ -0,0 +1,28 @@
cve: POSTCUT-002
alias: Upload validator TOCTOU — image swap between validate and move
cwe_primary: CWE-367
cwe_acceptable: [CWE-367, CWE-362, CWE-22, CWE-434]
target_file: source.py
vuln_lines: [25, 26, 34, 35, 36, 37]
severity: high
vuln_class: toctou_race
exploit_pattern_regex: '(toctou|race\s*condition|time[- ]of[- ]check|swap|replace.*file|symlink|inotify)'
must_mention_any:
- toctou
- race condition
- time-of-check
- validate then move
- swap file
- symlink
- between validation
- between check
- attacker replaces
points: 30
memorization_resistant: true
notes: |
Synthetic — novel pattern. Validate then move pattern with no atomic
handle: attacker can replace the file at tmp_path between validate_image()
(passes — real image) and shutil.move() (now moves the attacker's payload
e.g. a PHP shell). Symlink swap or inotify-timed replacement works.
X-Sendfile note hints that arbitrary content gets served regardless of
extension — broader impact.
@@ -0,0 +1,39 @@
# File upload validator — internal CMS, pre-fix.
# Validates uploaded image, then moves it into a public web-root.
import os, shutil, hashlib
from PIL import Image
UPLOAD_TMP = "/var/uploads/tmp"
PUBLIC_DIR = "/var/www/static/uploads"
ALLOWED_MIME = {"image/png", "image/jpeg", "image/gif"}
def validate_image(tmp_path):
"""Open with PIL to verify it's a real image. Returns True if valid."""
try:
with Image.open(tmp_path) as im:
im.verify() # raises on malformed
with Image.open(tmp_path) as im:
return im.format.lower() in ("png", "jpeg", "gif")
except Exception:
return False
def upload_user_avatar(user_id, tmp_path):
"""Upload flow: client puts file at UPLOAD_TMP/<user_id>.upload, this
function validates and promotes to PUBLIC_DIR."""
# 1. validate the file at tmp_path
if not validate_image(tmp_path):
os.remove(tmp_path)
return {"ok": False, "error": "not_an_image"}
# 2. compute hash for de-dup
with open(tmp_path, "rb") as f:
digest = hashlib.sha256(f.read()).hexdigest()
# 3. move the file to public location
dest = os.path.join(PUBLIC_DIR, f"{user_id}-{digest[:16]}.bin")
shutil.move(tmp_path, dest)
# 4. server serves it via X-Sendfile so the extension doesn't matter
return {"ok": True, "path": dest}