Skip to content

fix(security): harden URL handling, fix memory safety and race conditions#721

Open
grisutheguru wants to merge 3 commits intoTokTok:masterfrom
grisutheguru:fix/security-hardening-v2
Open

fix(security): harden URL handling, fix memory safety and race conditions#721
grisutheguru wants to merge 3 commits intoTokTok:masterfrom
grisutheguru:fix/security-hardening-v2

Conversation

@grisutheguru
Copy link
Copy Markdown

@grisutheguru grisutheguru commented Apr 20, 2026

Summary

Security hardening across 16 files addressing vulnerabilities found during a comprehensive code audit.

URL / Link Handling (remote-exploitable)

  • Block dangerous URI schemes (smb://, file://, ed2k://, ms-msdt:, search-ms:) in chat message links — prevents NTLM hash theft on Windows and local file probing
  • Confirmation dialog before opening any external URL — critical for Tor/proxy users: QDesktopServices::openUrl() opens the system browser which bypasses the Tox SOCKS5 proxy, revealing the user's real IP address
  • Block remote resource loading in CustomTextDocument::loadResource() — only allow key: (smileys) and qrc: schemes, preventing IP tracking via injected <img> tags
  • Remove file://, smb://, ed2k:// from clickable link regex in textformatter.cpp
  • Fix ReDoS in URI regex: fix malformed [\S| ] character class, add length cap

Memory Safety

  • Use-after-free in CoreVideoSource::unsubscribe(): replace delete this with deleteLater()
  • Use-after-free in CameraDevice::close(): acquire openDeviceLock before decrementing refcount
  • Uninitialized pointer ReadWriteLocker::lock_: add = nullptr
  • Double-free prevention: set inputBuffer = nullptr after delete[] in OpenAL::cleanupInput()
  • Integer truncation guard: bounds check before uint16_t cast of video frame dimensions
  • VPX frame validation: reject invalid dimensions (zero, odd, >4096)

Race Conditions

  • TOCTOU in VideoFrame::fromAVFrame: re-check after read-to-write lock upgrade
  • cancelCall() race: set/check isCancelling under callsLock

Crypto / Privacy

  • Wipe encryption key material: PassKeyDeleter zeroes key; deriveKey() wipes intermediate buffers
  • File permissions: new Paths::setSecureFilePermissions() (0600) applied to .tox save files

Platform / Hardening

  • Async-signal-safe crash handler: write(STDERR_FILENO) + _exit() instead of qCritical()/exit()
  • Predictable PRNG: std::random_device seed; QRandomGenerator instead of rand()
  • IPC busy-wait: msleep(50) + 30s cap instead of msleep(0) infinite loop
  • IPC username: getpwuid(getuid()) on POSIX instead of getenv("USER")
  • DB file swap: atomic rename() on POSIX with error checking
  • Profile name validation: isValidProfileName() rejects path traversal and reserved names
  • Conference title logic bug: fixed || to && in loadConferences()

Test plan

  • CI build passes on all platforms (Linux, macOS, Windows, Android, WASM)
  • Click a tox: URI in chat — should open directly without dialog
  • Click an https:// link in chat — should show confirmation dialog with IP warning
  • Click/paste an smb:// or file:// link — should be silently blocked
  • Video call: start/cancel/timeout — verify no crashes
  • Profile creation with ../, CON, NUL — should be rejected
  • Encrypted profile: open/close — verify database operations work
  • Kill qTox with SIGTERM — verify clean shutdown

🤖 Generated with Claude Code


This change is Reviewable

…ions

- Block dangerous URI schemes (smb://, file://, ed2k://) in chat links
  and show confirmation dialog before opening any external URL to protect
  Tor/proxy users from IP deanonymization
- Block remote resource loading in CustomTextDocument (only allow key:/qrc:)
- Fix use-after-free: replace delete-this with deleteLater() in
  CoreVideoSource, fix CameraDevice::close() lock ordering
- Fix TOCTOU race in VideoFrame::fromAVFrame lock upgrade
- Initialize ReadWriteLocker::lock_ to nullptr (was uninitialized)
- Fix cancelCall() race: check isCancelling under callsLock in callbacks
- Wipe encryption key material in PassKeyDeleter and deriveKey()
- Use async-signal-safe functions only in crash/signal handlers
- Replace rand()/clock-seeded mt19937 with std::random_device/QRandomGenerator
- Fix conference title logic bug (|| vs &&)
- Fix IPC busy-wait (msleep(50) + 30s cap), use getpwuid() over getenv
- Atomic rename() on POSIX for database file swap
- Add Profile::isValidProfileName() to prevent path traversal
- Add Paths::setSecureFilePermissions() for sensitive files (0600)
- Fix ReDoS in textformatter regex, remove dangerous URI patterns
- Validate VPX frame dimensions, add uint16_t bounds check
- Prevent OpenAL inputBuffer double-free

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 20, 2026

Tip

Preview URL:

@github-actions github-actions Bot added the bug Bug fix for the user, not a fix to a build script label Apr 20, 2026
Tox_Pass_Key is an opaque/incomplete type in toxcore's public API,
so sizeof() cannot be applied. Remove the manual wipe in PassKeyDeleter
(tox_pass_key_free handles cleanup). The intermediate buffer wipes in
deriveKey() are preserved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
QMutex is non-copyable, so operator[]= {} fails. Use bare operator[]
which default-constructs the entry in-place.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Bug fix for the user, not a fix to a build script

Development

Successfully merging this pull request may close these issues.

1 participant