Skip to content

fix(security): resolve all 40 open CodeQL alerts + check in 2 untracked files - #54

Merged
Star-Lotus merged 6 commits into
mainfrom
fix/security-alerts
Aug 11, 2026
Merged

fix(security): resolve all 40 open CodeQL alerts + check in 2 untracked files#54
Star-Lotus merged 6 commits into
mainfrom
fix/security-alerts

Conversation

@Star-Lotus

Copy link
Copy Markdown
Collaborator

Summary

Resolves all 40 open CodeQL alerts on main, grouped into atomic commits per rule for independent revert if needed. Also checks in 2 previously untracked files from design exploration.

Commits (one batch per rule)

Commit Batch Alerts
17557a3 chore: check in brand logo + color-check script
895af2e py/path-injection ×24 #6-15, #17-21, #23, #29-36
1fff152 py/command-line-injection ×6 + regression tests #3, #16, #25-28
75579f5 py/stack-trace-exposure ×2 #24, #41
da0b66f js/xss-through-dom ×3 + js/incomplete-sanitization ×3 #1, #2, #37-40
1748246 actions/missing-workflow-permissions + js/shell-command-injection #22, #45

Fix strategy (no behavior change for legitimate inputs)

  • path-injection: converged on the shared _safe_resolve_path helper (realpath + single provable startswith guard); multi-level legit paths like assets/characters/x.png still pass (pinned by tests). oss_utils.upload_file is fenced to output/ + system temp dir — callers degrade gracefully to data-URI/local (pinned by existing test_wan26_reference_local_without_oss_uses_data_uri). Upload endpoints sanitize file extensions through a dict allow-list returning literals.
  • command-line-injection: all 6 ffmpeg calls already used list args (no shell=True); the remaining taint entered via extract_last_frame's legacy absolute-path branch, now contained to output/. New tests/test_ffmpeg_path_safety.py includes a real ffmpeg end-to-end run (legit path extracts a frame; /etc/passwd and ../ attempts rejected).
  • stack-trace-exposure: generic client messages (type(exc).__name__), full details stay in server logs.
  • xss-through-dom: one shared barrier in getAssetUrl (new URL protocol allow-list http/https/blob + encodeURI) covers all 3 sinks.
  • incomplete-sanitization: first-match .replace chains → global regex /[*x]/g.
  • workflow permissions: top-level contents: read.
  • shell-command-injection: execFileSync with arg list in dev-setup.js.

Verification

  • pytest: 209 passed (incl. 8 new regression tests, real-ffmpeg happy path verified locally)
  • frontend: typecheck ✅ / vitest 124 passed ✅ / build ✅
  • No skipped alerts — none of the fixes required changing legitimate behavior semantics.

…-injection)

- pipeline._safe_resolve_path: simplify guard to a single startswith check
  so static analysis can prove containment (behavior unchanged for all
  callers, which always pass non-empty filenames)
- llm._resolve_image_for_vision: resolve candidates via realpath and only
  accept files inside the managed output/ tree
- media_refs: replace Path.resolve() checks with realpath + prefix guard
  in _is_under and resolve_local_media_path
- oss_utils.upload_file: restrict uploads to output/ and the system temp
  dir; callers fall back gracefully (data URI / local path) when refused
- api: sanitize uploaded file extensions through an allow-list map before
  embedding them in server-side paths (4 upload endpoints)
…nd-line-injection)

All six flagged subprocess.run(ffmpeg) calls already used list arguments
(no shell=True); the remaining taint entered through extract_last_frame's
legacy absolute-path branch which bypassed _safe_resolve_path. That branch
now realpath-resolves and requires containment in the managed output/ tree.

Adds tests/test_ffmpeg_path_safety.py pinning both directions:
- _safe_resolve_path accepts simple and multi-level relative paths,
  rejects ../ traversal, absolute escapes, and mixed traversal
- extract_last_frame rejects /etc/passwd style and ../ style video_url
- happy-path regression with a real ffmpeg run (lavfi-generated clip)
  proving frame extraction still works end-to-end
…QL py/stack-trace-exposure)

- pipeline.refine_batch_generator: SSE frame_refine_error event now sends
  a generic message with the exception class name; full details remain in
  the server log
- system_check: ffmpeg health-check failure message no longer embeds
  str(e); details are logged server-side instead
…rts)

- getAssetUrl: validate http/blob inputs with new URL() and an explicit
  protocol allow-list (http/https/blob) so javascript:-style values can
  never reach img/video src; local paths are encodeURI'd (covers 3
  js/xss-through-dom alerts through one shared barrier)
- playground size labels: replace first-match-only .replace('*'/'x')
  chains with a single global regex /[*x]/g (3 js/incomplete-sanitization
  alerts; output unchanged for well-formed WxH size strings)
- backend-ci.yml: add top-level 'permissions: contents: read' so the
  GITHUB_TOKEN gets only what the job needs
  (actions/missing-workflow-permissions)
- dev-setup.js: install Python deps via execFileSync with an argument
  list instead of interpolating the pip path into a shell string
  (js/shell-command-injection-from-environment)
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@Star-Lotus
Star-Lotus merged commit 551f65a into main Aug 11, 2026
6 of 7 checks passed
@Star-Lotus
Star-Lotus deleted the fix/security-alerts branch August 11, 2026 05:37
EthanDuan05 pushed a commit to EthanDuan05/lumenx that referenced this pull request Aug 14, 2026
…URLs

Round 2 for the 9 alerts CodeQL kept open after PR alibaba#54:
- py/command-line-injection x6: build ffmpeg output filenames from
  store-backed frame.id/script.id instead of request parameters, and
  coerce offset_ms to int before it enters the adelay filter string.
  Runtime values are identical (ids matched by lookup), so behavior
  is unchanged; the request-parameter taint chain is simply broken.
- js/xss-through-dom x3: strip HTML metacharacters from pass-through
  http/blob URLs in getAssetUrl (no-op for well-formed URLs).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants