From f06b6dcc7841bffe543be55412b1dbc5a913a9f8 Mon Sep 17 00:00:00 2001 From: kevinchennewbee <200705279@qq.com> Date: Sun, 14 Jun 2026 10:39:45 +0800 Subject: [PATCH] fix(wechat): sanitize media file_name to block path traversal in _dl_media MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `_dl_media` takes `file_name` straight from the inbound message payload (attacker-controllable) and joins it onto `_TEMP_DIR` before writing the decrypted bytes: fname = sub.get('file_name') or f'{uuid...}{ext}' p = os.path.join(_TEMP_DIR, fname); open(p, 'wb').write(pt) `os.path.join(base, '../../x')` (or an absolute path) escapes `_TEMP_DIR`, so a remote sender can write attacker-chosen content to an arbitrary path on the bot host — e.g. drop a file into an autoload location. It is a write primitive reachable by anyone who can message the bot. Fix: collapse the inbound name to its basename before use. A normal filename has no directory component, so basename is the identity for legitimate names and behavior is unchanged; only `../` / absolute paths are neutralized. Empty names still fall through to the uuid fallback. Co-Authored-By: Claude Opus 4.8 (1M context) --- frontends/wechatapp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/wechatapp.py b/frontends/wechatapp.py index 301f10c62..e56c9181f 100644 --- a/frontends/wechatapp.py +++ b/frontends/wechatapp.py @@ -284,7 +284,7 @@ def _dl_media(items): if sub.get('media', {}).get('aes_key') else bytes.fromhex(ak)) ct = requests.get(f'{CDN_BASE}/download?encrypted_query_param={quote(eq)}', headers={'User-Agent': UA}, timeout=60).content pt = AES.new(aes_key, AES.MODE_ECB).decrypt(ct); pt = pt[:-pt[-1]] - fname = sub.get('file_name') or f'{uuid.uuid4().hex[:8]}{ext or ".bin"}' + fname = os.path.basename(sub.get('file_name') or '') or f'{uuid.uuid4().hex[:8]}{ext or ".bin"}' p = os.path.join(_TEMP_DIR, fname); open(p, 'wb').write(pt) paths.append(p); print(f'[WX] media saved: {fname}', file=sys.__stdout__) except Exception as e: