cpp-security

v2026.09.24

C++ memory and concurrency safety: AddressSanitizer (ASan), UndefinedBehaviorSanitizer (UBSan), ThreadSanitizer (TSan), MemorySanitizer (MSan), MSVC `/sdl` and `/guard:cf`, CERT C++ secure coding rules, integer-overflow safe arithmetic, and Control Flow Integrity. USE WHEN: user mentions "ASan", "AddressSanitizer", "UBSan", "TSan", "MSan", "use-after-free", "buffer overflow", "undefined behavior", "data race", "CERT C++", "secure C++", "/sdl", "/GS", "ASLR", "DEP", "stack canary" DO NOT USE FOR: Web/app security (use `owasp`), .NET security (`dotnet-security`), cryptography APIs (use `cryptography`)

GitHub
安装命令
npx skhub add claude-dev-suite/cpp-security
Markdown
SKILL.md

C++ Security & Memory Safety - Quick Reference

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: cpp-security.

The Sanitizers (debug-time, near-zero false positives)

SanitizerCatchesOverheadNotes
ASanHeap/stack/global OOB, use-after-free, double-free, leaks~2xCannot combine with TSan/MSan
UBSanSigned overflow, null deref, OOB shift, misaligned access, etc.~10-20%Often combined with ASan
TSanData races between threads~5-15xCannot combine with ASan
MSanUse of uninitialized memory~3xRequires all deps instrumented (Clang only)
CFI (-fsanitize=cfi)Indirect-call integrity violationssmallRequires LTO

Enable in CMake

add_library(sanitizers_iface INTERFACE)
if(NOT MSVC)
    target_compile_options(sanitizers_iface INTERFACE
        -fsanitize=address,undefined -fno-omit-frame-pointer -g -O1)
    target_link_options(sanitizers_iface INTERFACE
        -fsanitize=address,undefined)
endif()
target_link_libraries(myapp PRIVATE sanitizers_iface)

Or per-preset (see cmake skill debug-asan example).

Run-time options

ASAN_OPTIONS=detect_leaks=1:abort_on_error=1:strict_string_checks=1 ./myapp
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1                    ./myapp
TSAN_OPTIONS=second_deadlock_stack=1:halt_on_error=1                ./myapp
LSAN_OPTIONS=suppressions=lsan.supp                                 ./myapp

CI tip: build a separate sanitizer job rather than slowing every test.

Compiler hardening flags

Linux/macOS (Clang/GCC)

-D_FORTIFY_SOURCE=3                     # libc bounds checks (needs -O1+)
-fstack-protector-strong                # stack canaries
-fstack-clash-protection                 # GCC: probe pages
-fcf-protection=full                    # x86: CET indirect-branch tracking
-Wformat -Wformat-security              # printf format-string attacks
-fPIE -pie                              # ASLR for executables
-Wl,-z,relro,-z,now                     # full RELRO
-Wl,-z,noexecstack                      # NX stack

Windows (MSVC)

/sdl                                    # all `/W4` security warnings + extra checks
/GS                                     # stack buffer overrun detection (default)
/guard:cf                               # Control Flow Guard
/guard:ehcont                           # EH continuation metadata (CET)
/Qspectre                               # Spectre mitigations
/DYNAMICBASE  /HIGHENTROPYVA            # ASLR (linker)
/NXCOMPAT                               # DEP
/CETCOMPAT                              # CET

Set per-target:

target_compile_options(myapp PRIVATE
    $<$<CXX_COMPILER_ID:MSVC>:/sdl /guard:cf /Qspectre>
    $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-fstack-protector-strong -D_FORTIFY_SOURCE=3>
)
target_link_options(myapp PRIVATE
    $<$<CXX_COMPILER_ID:MSVC>:/DYNAMICBASE /HIGHENTROPYVA /NXCOMPAT /CETCOMPAT /guard:cf>
    $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-pie -Wl,-z,relro,-z,now,-z,noexecstack>
)

CERT C++ — top categories with C++ idiomatic fixes

Use std::span / std::string_view instead of pointer + size

// BAD: easy to desync
void process(const char* buf, std::size_t n);

// GOOD
void process(std::span<const std::byte> buf);

Safe integer arithmetic

#include <limits>
#include <stdexcept>

template <std::integral T>
T checked_add(T a, T b) {
    T r;
    if (__builtin_add_overflow(a, b, &r))         // GCC/Clang; MSVC: <intsafe.h> IntAdd*
        throw std::overflow_error("add overflow");
    return r;
}

C++26 will land <numeric> add_sat, sub_sat, mul_sat, div_sat as standard.

Avoid printf with non-literal format strings

printf(user_input);             // BAD - format-string vuln
std::print("{}", user_input);   // GOOD - C++23 std::print/format

Validate at boundaries, trust internally

Once data is parsed into a typed value, downstream code should not re-validate. Concentrate validation at the deserialization layer.

Prefer enum class to avoid implicit conversions

enum class Permission { None = 0, Read = 1, Write = 2, Admin = 4 };

Don't slice polymorphic types

struct Base { virtual ~Base() = default; };
struct Derived : Base { int extra{}; };

void take(Base b);      // BAD - slices Derived state
void take(const Base&); // GOOD

Concurrency safety

// BAD: data race on `count`
int count = 0;
auto worker = [&] { for (int i = 0; i < 1'000'000; ++i) ++count; };

// GOOD
std::atomic<int> count{0};
auto worker = [&] { for (int i = 0; i < 1'000'000; ++i) count.fetch_add(1, std::memory_order_relaxed); };

Build the same binary under TSan in CI to catch latent races; relying on "we tested it" misses races that surface only on different hardware/OS.

Common Vulnerability Patterns and Their C++ Fixes

VulnerabilityBad patternModern C++ fix
Buffer overflowchar buf[64]; strcpy(buf, x);std::string or std::span + bounds-checked algorithms
Use-after-freeReturning pointer to localReturn by value (RVO) or std::unique_ptr
Format stringprintf(input)std::format("{}", input)
Integer overflow → OOBnew T[n * sizeof(T)]std::vector<T>(n) (allocator throws on overflow)
TOCTOU file raceif (access("x")) open("x");open() then check errno (atomic intent)
Iterator invalidationMutating container while iteratingUse index, or rebuild iterator after mutation
Uninitialized readint x; use(x);int x{}; or initialize at decl point
Dangling reference to temporaryauto&& s = std::string{"x"}.c_str();Bind by value, or extend lifetime explicitly

Fuzzing (for parsers, decoders, anything taking untrusted input)

// fuzz_target.cpp
#include <cstdint>
#include <cstddef>
#include "parser.hpp"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    try { (void) parse(std::span<const uint8_t>(data, size)); }
    catch (...) { /* parser may throw on bad input - that's fine */ }
    return 0;
}

Build with clang -fsanitize=fuzzer,address,undefined fuzz_target.cpp parser.cpp.

Anti-Patterns

Anti-PatternWhy It's BadCorrect Approach
Disabling ASan after a CI failureHides real bugsFix the bug; keep sanitizer on
reinterpret_cast to silence the compilerAlmost always UBstatic_cast + redesign types, or std::bit_cast (C++20)
std::memcpy of non-trivially-copyable typesUBConstruct/move properly
Catching std::exception& and ignoringLoses diagnosticsRe-throw or log + handle
new T[n] with n from inputInteger overflow → tiny alloc, big writestd::vector<T>(n) (throws bad_alloc)
Hand-rolled crypto/hashSubtle errors, side channelsUse libsodium / OpenSSL / Botan
C-style cast (T)xHides reinterpret/const-castC++ casts so the intent is reviewable
发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

skills/security/cpp-security

默认分支

main

最新提交

9496306

Tree SHA

fe4e2f1