-
Notifications
You must be signed in to change notification settings - Fork 562
fix path traversal vulnerability in audio file path parameters #343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix path traversal vulnerability in audio file path parameters #343
Conversation
📝 WalkthroughWalkthroughAdds internal audio path validation via Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
acestep/api_server.py (1)
2171-2222:⚠️ Potential issue | 🟠 MajorPrevent duplicate keyword arguments when overriding audio paths.
_build_request()explicitly setsreference_audio_pathandsrc_audio_pathfrom parsed parameters, but three call sites (multipart/form-data, form-urlencoded, and raw request handlers) also pass these as keyword arguments. This causesTypeError: got multiple values for keyword argument.✅ Suggested fix (allow overrides without duplicates)
def _build_request(p: RequestParser, **kwargs) -> GenerateMusicRequest: """Build GenerateMusicRequest from parsed parameters.""" + reference_audio_path = kwargs.pop("reference_audio_path", None) + src_audio_path = kwargs.pop("src_audio_path", None) + reference_audio_path = _validate_audio_path(reference_audio_path or p.str("reference_audio_path") or None) + src_audio_path = _validate_audio_path(src_audio_path or p.str("src_audio_path") or None) return GenerateMusicRequest( prompt=p.str("prompt"), lyrics=p.str("lyrics"), thinking=p.bool("thinking"), analysis_only=p.bool("analysis_only"), full_analysis_only=p.bool("full_analysis_only"), sample_mode=p.bool("sample_mode"), sample_query=p.str("sample_query"), use_format=p.bool("use_format"), model=p.str("model") or None, bpm=p.int("bpm"), key_scale=p.str("key_scale"), time_signature=p.str("time_signature"), audio_duration=p.float("audio_duration"), vocal_language=p.str("vocal_language", "en"), inference_steps=p.int("inference_steps", 8), guidance_scale=p.float("guidance_scale", 7.0), use_random_seed=p.bool("use_random_seed", True), seed=p.int("seed", -1), batch_size=p.int("batch_size"), repainting_start=p.float("repainting_start", 0.0), repainting_end=p.float("repainting_end"), instruction=p.str("instruction", DEFAULT_DIT_INSTRUCTION), audio_cover_strength=p.float("audio_cover_strength", 1.0), - reference_audio_path=_validate_audio_path(p.str("reference_audio_path") or None), - src_audio_path=_validate_audio_path(p.str("src_audio_path") or None), + reference_audio_path=reference_audio_path, + src_audio_path=src_audio_path, task_type=p.str("task_type", "text2music"), use_adg=p.bool("use_adg"), cfg_interval_start=p.float("cfg_interval_start", 0.0), cfg_interval_end=p.float("cfg_interval_end", 1.0), infer_method=p.str("infer_method", "ode"), shift=p.float("shift", 3.0), audio_format=p.str("audio_format", "mp3"), use_tiled_decode=p.bool("use_tiled_decode", True), lm_model_path=p.str("lm_model_path") or None, lm_backend=p.str("lm_backend", "vllm"), lm_temperature=p.float("lm_temperature", LM_DEFAULT_TEMPERATURE), lm_cfg_scale=p.float("lm_cfg_scale", LM_DEFAULT_CFG_SCALE), lm_top_k=p.int("lm_top_k"), lm_top_p=p.float("lm_top_p", LM_DEFAULT_TOP_P), lm_repetition_penalty=p.float("lm_repetition_penalty", 1.0), lm_negative_prompt=p.str("lm_negative_prompt", "NO USER INPUT"), constrained_decoding=p.bool("constrained_decoding", True), constrained_decoding_debug=p.bool("constrained_decoding_debug"), use_cot_caption=p.bool("use_cot_caption", True), use_cot_language=p.bool("use_cot_language", True), is_format_caption=p.bool("is_format_caption"), allow_lm_batch=p.bool("allow_lm_batch", True), **kwargs, )
add validation for reference_audio_path and src_audio_path to reject absolute paths and directory traversal sequences. applies to all request parsing entry points (json, multipart form, url-encoded form, raw body). also fix duplicate keyword argument bug in _build_request by popping audio path overrides from kwargs before expansion.
87a0115 to
9a83bf9
Compare
|
@coderabbitai can you check again? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
acestep/api_server.py (1)
2173-2202:⚠️ Potential issue | 🟠 MajorMultipart uploads will now 400 because temp paths are absolute.
Overrides passed from multipart uploads are server-generated absolute paths, so validating them as user input rejects every upload. Only validate when the value comes from the parser, and trust explicit overrides (already validated or server-generated).Suggested fix
def _build_request(p: RequestParser, **kwargs) -> GenerateMusicRequest: """Build GenerateMusicRequest from parsed parameters.""" - # Pop audio path overrides from kwargs to avoid duplicate keyword arguments - # when callers (multipart/form, url-encoded, raw body) pass them explicitly. - ref_audio = kwargs.pop("reference_audio_path", None) or p.str("reference_audio_path") or None - src_audio = kwargs.pop("src_audio_path", None) or p.str("src_audio_path") or None + # Prefer explicit overrides (already validated or server-generated). + ref_audio = kwargs.pop("reference_audio_path", None) + if ref_audio is None: + ref_audio = _validate_audio_path(p.str("reference_audio_path") or None) + src_audio = kwargs.pop("src_audio_path", None) + if src_audio is None: + src_audio = _validate_audio_path(p.str("src_audio_path") or None) return GenerateMusicRequest( prompt=p.str("prompt"), lyrics=p.str("lyrics"), @@ - reference_audio_path=_validate_audio_path(ref_audio), - src_audio_path=_validate_audio_path(src_audio), + reference_audio_path=ref_audio, + src_audio_path=src_audio, task_type=p.str("task_type", "text2music"),
|
✅ Actions performedReview triggered.
|
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain
🏁 Script executed: Length of output: 127218
✅ Security ValidationThe 1. Absolute Path Protection
2. Directory Traversal Protection
3. Comprehensive Coverage
Minor Observations
Test Cases Verified# Blocked ❌
"../../etc/passwd" # Directory traversal
"/etc/passwd" # Absolute Unix path
"C:\\Windows\\System32" # Absolute Windows path
"audio/../../file.mp3" # Escapes parent directory
# Allowed ✓
"audio/file.mp3" # Normal relative path
"audio/subdir/file.mp3" # Nested relative path
"audio/../other/file.mp3" # Traversal within allowed scope (resolves to "other/file.mp3")The implementation is production-ready and effectively mitigates the path traversal vulnerability! 🔒 |
|
@coderabbitai does it pass all the tests? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain
🏁 Script executed: Length of output: 1873 🏁 Script executed: Length of output: 3981 🏁 Script executed: Length of output: 4490
🔍 Testing Infrastructure StatusNo formal unit tests exist:
What exists:
✅ Manual Verification OptionsSince there are no automated tests, you'll need to verify the changes manually: Option 1: Use the existing client test script # Start your API server first, then:
python -m openrouter.client_test --test allThis will verify the API endpoints still work (but won't specifically test path traversal prevention). Option 2: Manual curl tests # These should be REJECTED (400 error):
curl -X POST http://localhost:8000/generate \
-H "Content-Type: application/json" \
-d '{"reference_audio_path": "../../etc/passwd", "prompt": "test"}'
curl -X POST http://localhost:8000/generate \
-H "Content-Type: application/json" \
-d '{"src_audio_path": "/etc/passwd", "prompt": "test"}'
# These should be ACCEPTED:
curl -X POST http://localhost:8000/generate \
-H "Content-Type: application/json" \
-d '{"reference_audio_path": "audio/file.mp3", "prompt": "test"}'Option 3: Write unit tests Answer to your question: No automated tests exist to run, so the changes haven't been tested by any test suite. Manual testing is required to verify the functionality. |
|
This "fix" results in a code 400 when you are using the API with uploaded audio, because it also trips with its own temp file where the audio is uploaded to. The checks are too strict and should not trip on the temp folder. I did a pr for this: #383 |
|
like @goedzo said, this breaks the upload file feature, and you can't make covers. |
add validation for reference_audio_path and src_audio_path to reject absolute paths and directory traversal sequences. applies to all request parsing entry points (json, multipart form, url-encoded form, raw body).
Summary by CodeRabbit