Skip to content

security: fix CodeQL path-injection, stack-trace-exposure, and weak-crypto alerts - #60

Open
LoggeL wants to merge 1 commit into
mainfrom
security/codeql-fixes
Open

security: fix CodeQL path-injection, stack-trace-exposure, and weak-crypto alerts#60
LoggeL wants to merge 1 commit into
mainfrom
security/codeql-fixes

Conversation

@LoggeL

@LoggeL LoggeL commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes all 31 open CodeQL code-scanning alerts.

Path Injection (24 alerts — high)

Files: src/utils/file_handling.py (9), src/routes/admin.py (15)

Added _validate_song_path() helper using pathlib.Path.resolve() + relative_to() containment check. Applied in get_song_dir() and delete_track() — the two functions where user-supplied track IDs are joined with SONGS_PATH. Since all 15 flagged path operations in admin.py route through get_song_dir(), fixing it at the source closes every taint flow from URL parameter → filesystem.

Path Injection in reference_lyrics (3 alerts — high)

File: src/services/reference_lyrics.py

Added _validate_file_path() that verifies vocals_path resolves within the songs directory before the file is opened in _fetch_openrouter(). Prevents crafted paths from reaching open().

Stack Trace Exposure (3 alerts — medium)

File: src/routes/admin.py

Location Fix
fetch_reference_lyrics Replaced f"Lyrics fetch failed: {e}" with generic message; full trace logged via logging.exception()
fetch_reference_lyrics_ai Same pattern
compress_songs Replaced print(f"...{e}") with logging.warning(exc_info=True)
song_details Removed stack_trace field from API response

Weak Cryptographic Algorithm (1 alert — high)

File: src/services/deezer.py

Replaced Crypto.Hash.MD5 with hashlib.md5(data, usedforsecurity=False). MD5 is integral to the Deezer download protocol (URL key generation + Blowfish key derivation) and cannot be swapped for SHA-256. The usedforsecurity=False flag (Python 3.9+) explicitly marks this as non-security use, which CodeQL recognizes as an acceptable exemption.

Verification

All four modules import successfully under the project venv. MD5 output verified identical to previous implementation (md5hex(b"hello") produces the expected 5d41402abc4b2a76b9719d911017c592). Path traversal tests confirm _validate_song_path() rejects both absolute (/etc/passwd) and relative (../../etc/passwd) escapes.

…rypto alerts

Path injection (24 alerts across 3 files):
- src/utils/file_handling.py: Add _validate_song_path() helper using
  pathlib.Path.resolve() + relative_to() containment check. Apply it
  in get_song_dir() and delete_track() to ensure all paths derived from
  user-supplied track IDs resolve strictly within SONGS_PATH.
- src/routes/admin.py: All 15 flagged path operations route through
  get_song_dir() which now validates containment, closing the taint
  flow from URL parameter to filesystem.
- src/services/reference_lyrics.py: Add _validate_file_path() to verify
  vocals_path is within the songs directory before opening in
  _fetch_openrouter().

Stack trace exposure (3 alerts in admin.py):
- fetch_reference_lyrics: Replace f'...{e}' response with generic
  message; log full exception server-side via logging.exception().
- fetch_reference_lyrics_ai: Same pattern — generic response +
  server-side logging.
- compress_songs: Replace print(f'...{e}') with logging.warning().
- song_details: Remove stack_trace field from API response to avoid
  exposing internal tracebacks to clients.

Weak cryptographic algorithm (1 alert in deezer.py):
- Replace Crypto.Hash.MD5 with hashlib.md5(usedforsecurity=False).
  MD5 is required by the Deezer download protocol for URL generation
  and Blowfish key derivation — it cannot be replaced with a different
  algorithm. The usedforsecurity=False flag (Python 3.9+) explicitly
  marks this as non-security use, satisfying CodeQL.

Raises ValueError if the resolved path escapes SONGS_PATH.
"""
resolved = Path(path).resolve()
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.

2 participants