Compare commits

..

1 Commits

Author SHA1 Message Date
7d7615f10d fix(security): prevent CWE-134 format string injection
All checks were successful
CI Code / Check spelling (pull_request) Successful in 18s
CI Code / Check coding style (pull_request) Successful in 32s
CI Code / Code Coverage (pull_request) Successful in 5m1s
CI Code / Linux (ubuntu) (pull_request) Successful in 6m19s
CI Code / Linux (arch) (pull_request) Successful in 6m23s
CI Code / Linux (debian) (pull_request) Successful in 9m10s
- add "%s" to unsafe cons_show/log_*/win_println calls
- add check-cwe134.sh static analysis script
- integrate security check into CI pipeline

Closes #85
2026-02-05 18:12:52 +03:00
7 changed files with 15 additions and 23 deletions

View File

@@ -50,9 +50,6 @@ jobs:
run: |
grep -P 'auto_(char|gchar|gcharv|guchar|jid|sqlite|gfd|FILE)[\w *]*;$' -r src && exit -1 || true
- name: Check CWE-134 format string vulnerabilities
run: ./check-cwe134.sh
- name: Install clang-format
run: |
sudo apt-get update

View File

@@ -144,16 +144,6 @@ scan-build make
scan-view ...
```
### Security checks
We have a static analyzer `check-cwe134.sh` that detects CWE-134 format string vulnerabilities. It runs automatically in CI but you can also run it locally:
```bash
./check-cwe134.sh
```
This checks for unsafe patterns where user-controlled data could be passed directly as a format string to functions like `cons_show`, `log_error`, `win_println`, etc. Always use `"%s"` format specifier when printing user data.
### Finding typos
We include a `.codespellrc` configuration file for `codespell` in the root directory.

View File

@@ -168,6 +168,10 @@ num_cores()
# Run test failure detection verification first
verify_test_failure_detection
# Run CWE-134 format string vulnerability check
echo "=== Running CWE-134 security check ==="
./check-cwe134.sh || { echo "CWE-134 check failed!"; exit 1; }
# Parse arguments
COVERAGE_ONLY=no
for arg in "$@"; do

View File

@@ -77,8 +77,6 @@ _db_teardown(const char* ctx)
}
g_chatlog_database = NULL;
}
// Safe to call unconditionally; no-op if not initialized.
// See: https://www.sqlite.org/c3ref/initialize.html
sqlite3_shutdown();
}

View File

@@ -148,8 +148,7 @@ create_input_window(void)
* Fail gracefully instead of aborting in production.
*/
if (MB_CUR_MAX > PROF_MB_CUR_MAX) {
log_error("Locale MB_CUR_MAX (%zu) exceeds compiled limit (%d)", (size_t)MB_CUR_MAX, PROF_MB_CUR_MAX);
cons_show_error("Unsupported locale. Before running, execute in terminal: export LC_ALL=C.UTF-8");
cons_show_error("Your locale's MB_CUR_MAX (%zu) exceeds PROF_MB_CUR_MAX (%d); input window disabled.", (size_t)MB_CUR_MAX, PROF_MB_CUR_MAX);
return;
}
#ifdef NCURSES_REENTRANT
@@ -168,7 +167,7 @@ create_input_window(void)
inp_win = newpad(1, INP_WIN_MAX);
if (!inp_win) {
log_error("Failed to allocate input window pad");
// Failed to allocate input pad; leave inp_win NULL and avoid further use
return;
}
wbkgd(inp_win, theme_attrs(THEME_INPUT_TEXT));

View File

@@ -40,8 +40,6 @@
#include <string.h>
#include <stdlib.h>
#include "log.h"
#ifdef HAVE_NCURSESW_NCURSES_H
#include <ncursesw/ncurses.h>
#elif HAVE_NCURSES_H
@@ -114,7 +112,6 @@ status_bar_init(void)
int row = screen_statusbar_row();
int cols = getmaxx(stdscr);
if (cols <= 0) {
log_warning("status_bar_init: invalid cols %d, defaulting to 1", cols);
cols = 1;
}
statusbar_win = newwin(1, cols, row, 0);
@@ -160,7 +157,6 @@ status_bar_resize(void)
}
int cols = getmaxx(stdscr);
if (cols <= 0) {
log_warning("status_bar_resize: invalid cols %d, defaulting to 1", cols);
cols = 1;
}
werase(statusbar_win);

View File

@@ -79,7 +79,15 @@ static void _win_print_wrapped(WINDOW* win, const char* const message, size_t in
static int
_check_subwin_width(int cols, int width)
{
return cols <= 1 ? 1 : CLAMP(width, 1, cols - 1);
if (cols > 1) {
if (width < 1)
width = 1;
if (width >= cols)
width = cols - 1;
} else {
width = 1;
}
return width;
}
int