Skip to content

Multiple security vulnerabilities: null dereference, SQL injection, buffer overflow, TOCTOU race conditions, command injection

High
matteius published GHSA-cv53-mq7p-6jp2 Mar 2, 2026

Software

lightNVR

Affected versions

<= 0.27.4

Patched versions

0.28.0

Description

Summary

This advisory covers a set of security vulnerabilities identified by CodeQL static analysis in lightNVR. All issues were initially addressed in commit d558e69 and are fully resolved in the 0.28.0 release, which also includes additional security hardening from a broader code audit.

Vulnerabilities

CWE-476: Null Pointer Dereference (code cleanup)

  • File: src/video/stream_protocol.c:510
  • Alert #39: CodeQL flagged a redundant null check on input_ctx after the pointer had already been validated at function entry. The redundant guard was not itself a vulnerability — the entry-point check already prevented null dereference — but the dead branch was misleading and has been removed for clarity.
  • Fix: Removed the redundant if (input_ctx) check; validation occurs at function entry.

CWE-89: SQL Injection via Unvalidated Migration File Path

  • File: src/database/sqlite_migrate.c
  • Alert #16: Migration file content was read and passed directly to sqlite3_exec() without verifying the file came from the trusted migrations directory.
  • Original fix (d558e69): Added strncmp()-based path prefix validation in apply_migration() and rollback_migration().
  • Hardened fix (1bdf6fe): Replaced strncmp() with realpath() canonicalization of both the file path and the migrations directory before comparison, preventing /../ traversal sequences from bypassing the prefix check. An additional boundary check ensures the resolved path is strictly within (not merely a prefix match of) the migrations directory. The validate_migration_file_security() function also verifies the file is a regular file (via lstat()) and is not world-writable, and validate_migration_sql() allowlists permitted SQL statement types.

CWE-134: Buffer Overflow from Unchecked snprintf Return Values

  • Files: src/database/db_query_builder.c:83,88, src/database/db_zones.c:31,33, src/video/go2rtc/go2rtc_api.c:376,378
  • Alerts #40-45: snprintf() return values were not checked; a truncated write could cause silent data corruption or logic errors.
  • Fix: Added if (written < 0 || (size_t)written >= remaining) checks after every snprintf() call in the affected functions, returning an error on truncation.

CWE-367: TOCTOU Race Conditions (Time-of-check Time-of-use)

chmod via path instead of fd

  • Files: src/core/daemon.c:266, src/video/hls/hls_directory.c:84,96, src/video/hls_writer.c:457
  • Alerts #25, #32, #33, #34: chmod(path, mode) called after file creation; an attacker could replace the path between the creation and the chmod.
  • Fix: Replaced with open(O_RDONLY|O_DIRECTORY|O_NOFOLLOW) + fchmod(fd, mode) + close(fd) pattern.

stat() check before file operation

  • Files: src/database/db_backup.c:110, src/storage/storage_manager.c:225, src/web/api_handlers_recordings_backend_agnostic.c:249,338,474, src/web/api_handlers_recordings_files_backend_agnostic.c:119
  • Alerts #26, #28, #35, #36, #37, #38: stat() used to check existence before fopen() or unlink(); file state can change between the check and the operation.
  • Fix: Removed stat() checks; attempt the operation directly and handle errno == ENOENT for the "does not exist" case.

stat() following symlinks before unlink/chmod

  • Files: src/storage/storage_manager.c:460, src/video/ffmpeg_utils.c:416, src/video/hls/hls_directory.c:439,476
  • Alerts #27, #29, #30, #31: stat() was used before unlink() or chmod() operations; by following symlinks it could be deceived into operating on the wrong file.
  • Fix: Replaced stat() with lstat() to avoid following symlinks; added S_ISREG / S_ISLNK checks before destructive operations.

CWE-78: Command Injection via popen() Shell Commands

  • File: src/web/api_handlers_system.c
  • User-controlled storage_path was interpolated into du -sb <path> and find <path> ... shell commands via popen().
  • Fix: Replaced all three popen() disk-size calls with a native get_directory_size() function that uses opendir()/readdir()/lstat() recursion.
  • File: src/web/api_handlers_settings.c
  • The storage_path and storage_path_hls settings accepted arbitrary user input.
  • Fix: Added is_safe_storage_path() validator that rejects paths containing shell metacharacters before the value is stored.

Affected Versions

All versions prior to 0.28.0 (i.e., 0.27.4 and earlier).

Patched Version

0.28.0 — includes the original fix commit d558e69 (security: fix CodeQL alerts #16,#25-45), the hardened migration path validation in 1bdf6fe, plus additional security hardening from a comprehensive code audit.

Acknowledgements

  • Vulnerabilities identified via CodeQL static analysis.
  • Isaac Richter for reporting that the initial strncmp()-based migration path validation was insufficient against /../ traversal, and for feedback on the CWE-476 advisory description.

Severity

High

CVE ID

No known CVE

Weaknesses

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component. Learn more on MITRE.

Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data. Learn more on MITRE.

Use of Externally-Controlled Format String

The product uses a function that accepts a format string as an argument, but the format string originates from an external source. Learn more on MITRE.

Time-of-check Time-of-use (TOCTOU) Race Condition

The product checks the state of a resource before using that resource, but the resource's state can change between the check and the use in a way that invalidates the results of the check. Learn more on MITRE.

NULL Pointer Dereference

The product dereferences a pointer that it expects to be valid but is NULL. Learn more on MITRE.