Native C/C++ Project Setup & Hardening
Assess a cross-platform modern-C++ (C++17) project — especially a Node.js native addon
built with node-gyp and node-addon-api — against a practical, evidence-based baseline for
build hardening, analysis tooling, portability, and maintainable code. Report applicable
preventive-control gaps even when no defect is currently proven, while clearly
distinguishing hardening advice from actual bugs.
Use the OpenSSF Compiler Options Hardening Guide as the compiler/linker backbone, the
C++ Core Guidelines for code conventions, CERT C/C++ and the sanitizer/tool docs
for analysis, and official node-gyp / Node-API documentation for the addon toolchain. See
ATTRIBUTION.md.
Boundary with resource review
Keep this skill separate from resource-review:
This skill (project-setup) |
The resource-review skill |
| Asks whether applicable controls meet a baseline |
Asks whether a memory/resource defect exists |
| Reports evidence-backed best-practice gaps |
Reports only proven defects |
| Uses Met / Gap / Not applicable / Needs verification |
Uses Critical / High / Medium / Low |
| Prioritizes Essential / Recommended / Optional |
Prioritizes impact and trigger reachability |
A missing stack protector or an unset sanitizer job is a hardening Gap, not a
vulnerability. If the assessment uncovers an actual defect (a real leak, use-after-free,
or race), list it separately under Escalate to resource review and recommend
the resource-review skill; do not mix it into hardening counts or assign it a CVSS-style
severity.
Core rules
- Applicability before compliance. Profile the project and select only controls that
match its real build systems, target OSes/arches, threading, prebuild strategy, and
vendored dependencies.
- Effective behavior over presence. A flag in one
conditions branch, a sanitizer
script that never runs in CI, or a .clang-tidy with WarningsAsErrors: '' is not
proof the control is effective on the shipped build.
- Research globally, report locally. Read the whole
binding.gyp/CMake, CI workflows,
scripts, and common.gypi defaults to resolve what the compiler actually receives;
report only on the requested scope.
- Credit toolchain defaults. Mark a control Met when the toolchain or node-gyp
common.gypi already provides it (MSVC /GS, /DYNAMICBASE, /NXCOMPAT are on by
default; Release builds optimize). Do not flag a default-on protection as missing.
- Arch-gate the dangerous flags. Some hardening flags hard-error on the wrong
architecture (
-fcf-protection=full is x86-only; -mbranch-protection is arm64-only).
Recommending them ungated breaks the build — always require a target_arch condition.
- No cargo-cult controls. Record Not applicable when a control has no relevant surface
(TSan on a strictly single-threaded synchronous addon;
-Wl,-z,* on a macOS-only
build), with one-line reasoning.
- Sanitizer-aware.
_FORTIFY_SOURCE must be off in AddressSanitizer builds.
Standard-library hardening assertions are independent and may remain enabled unless the
project's exact toolchain demonstrates a conflict; a hardening recommendation that breaks
the sanitizer build is a Gap, not an improvement.
- No auto-apply. Propose changes; edit only when the user explicitly asks.
Control states and priorities
Every assessed control has exactly one state:
| State |
Meaning |
| Met |
Effective implementation is evidenced in build config, CI, or toolchain default |
| Gap |
Control applies and evidence shows it is absent, disabled, or materially incomplete |
| Not applicable |
The project lacks the surface (no Windows target, no threads, no prebuilds, …) |
| Needs verification |
The control applies, but a required fact (toolchain version, CI behavior) cannot be established statically |
Prioritize gaps by risk reduction, not by fear:
| Priority |
Use when |
| Essential |
A broadly expected boundary is missing on a security-sensitive surface: no stack protector/FORTIFY on code doing raw buffer/memcpy work; C++ exceptions able to cross the C ABI; mutable global state in a worker-capable addon; over-broad sanitizer suppressions masking first-party leaks |
| Recommended |
Meaningful hardening with clear applicability: full RELRO (-Wl,-z,relro -Wl,-z,now), UBSan+TSan in CI, -fvisibility=hidden on C++ TUs, an oldest-glibc prebuild, arch-gated CFI |
| Optional |
Context-dependent defense-in-depth or maturity: -fstrict-flex-arrays=3, -ftrivial-auto-var-init=zero, -D_GLIBCXX_ASSERTIONS in release, extra CI telemetry |
Do not use priority as a disguised severity. Consider exposure (does untrusted input
reach the native code?), what the code actually does, existing compensating controls, and
implementation/toolchain cost.
Review workflow
Run these steps in order. Load reference files only when their domains apply.
1. Resolve scope
2. Build the project profile
Establish from config rather than assumptions (read
references/build-and-toolchain.md):
- build system(s): node-gyp/
binding.gyp, CMake, or both; node-addon-api and
NAPI_VERSION; NAPI_CPP_EXCEPTIONS;
- language standard and how it is set per platform;
- target OSes (Linux glibc/musl, macOS, Windows) and arches (x64, arm64);
- prebuild strategy (prebuildify/node-gyp-build, prebuild) and shipped binaries;
- concurrency: worker threads,
AsyncWorker, threadsafe functions, shared state;
- vendored C/C++ sources (amalgamations) and how they are pinned/updated;
- CI matrix, sanitizer/analysis jobs, and release/publish flow.
State unresolved assumptions in the report.
3. Select the baseline
Read references/baseline-and-reporting.md. Pin
the compiler/linker baseline to the OpenSSF Compiler Options Hardening Guide and the
code baseline to the C++ Core Guidelines; verify version-sensitive flag availability
against the project's actual toolchain floor (for example the oldest glibc/GCC used by its
prebuild container). Never assert a flag exists without confirming it for that toolchain.
4. Select applicable domains
| Detected surface |
Load |
| Always |
baseline-and-reporting.md, build-and-toolchain.md |
| Any compiled C/C++ (all real projects) |
compiler-hardening.md |
| Any project that can build under a sanitizer / static analyzer |
sanitizers-and-analysis.md |
| Ships prebuilt binaries, multi-OS/arch, vendors C sources |
ci-and-release.md |
| Hand-written C++ (RAII, ownership, threading, C-ABI boundary) |
modern-cpp-conventions.md |
5. Gather evidence
For each applicable control:
- read the effective flags the compiler/linker receive for the Release build on each
OS/arch, not just one
conditions branch;
- confirm CI actually runs and gates on the control (a sanitizer job whose zero exit is
never checked, or
clang-tidy with WarningsAsErrors: '', is advisory, not enforced);
- credit toolchain and
common.gypi defaults; account for arch/OS applicability;
- record
file:line evidence for Met and Gap; use Needs verification for a concrete
missing fact (a toolchain version, whether a CI job blocks merge), phrased as a question.
Presence of a flag in the file is a lead; effectiveness on the shipped build is the
finding.
6. Consolidate
Group repeated misses under the narrowest common remediation (one missing POSIX hardening
block covering every non-Windows TU is one Gap, not one per file). Separate controls when
OS/arch applicability or remediation differs.
7. Report
Use the structure in baseline-and-reporting.md:
## Native Setup & Hardening Review: <scope>
**Project profile:** <build systems, targets/arches, prebuilds, threading, vendored deps>
**Baseline:** OpenSSF Compiler Hardening Guide + C++ Core Guidelines
**Assumptions:** <unresolved toolchain/CI facts>
### Coverage Summary
| Domain | Met | Gap | Needs verification | Not applicable |
|--------|----:|----:|-------------------:|---------------:|
### Essential Gaps
#### [HARDEN-001] <control> — Gap
- **Applicability:** Why this control applies to this project.
- **Evidence:** `file:line` and the effective build behavior observed.
- **Recommendation:** Minimal concrete change (arch-gated where required).
- **Tradeoffs:** Toolchain floor, startup cost, sanitizer-build interaction.
- **Source:** OpenSSF/Core Guidelines/vendor reference.
### Recommended Gaps
...
### Optional Improvements
...
### Needs Verification
...
### Controls Already Met
### Not Applicable
### Remediation Roadmap
1. Now — Essential, low-risk, arch-gated fixes.
2. Next — Recommended controls and CI gating.
3. Later — Optional defense-in-depth.
### Escalate to Resource Review
Only concrete defects, excluded from hardening counts — recommend the `resource-review` skill.
If no gaps remain, say which profile/baseline was assessed and that all applicable
controls examined were Met; still list unresolved verification questions.
Source freshness
Prefer primary sources in this order:
- OpenSSF Compiler Options Hardening Guide for the flag baseline.
- Compiler/linker vendor docs (GCC, Clang/LLVM, Microsoft Learn) for exact flag behavior,
arch applicability, and minimum toolchain version.
- C++ Core Guidelines and cppreference for code conventions.
- Sanitizer/tool docs (AddressSanitizer, clang-tidy, Valgrind) and node-gyp/Node-API
docs for tooling and addon specifics.
When internet access is available, verify version-sensitive flags against the project's
toolchain floor. Never use listicles as normative sources. When offline, use the pinned
references and state that current toolchain behavior was not re-verified.
References
| File |
Covers |
references/baseline-and-reporting.md |
Standards backbone, profile-driven applicability, evidence rules, state/priority calibration, report format |
references/build-and-toolchain.md |
binding.gyp anatomy, node-addon-api/NAPI_VERSION, standard selection, symbol visibility/prefixing, vendoring, Windows arch traps |
references/compiler-hardening.md |
Per-OS/per-arch compiler & linker hardening flag matrix (GCC/Clang + MSVC), arch-gating, FORTIFY-vs-sanitizer, the .node-is-a-shared-library reality |
references/sanitizers-and-analysis.md |
Wiring ASan/UBSan/TSan/LSan/Valgrind and clang-tidy/cppcheck; running them against a Node addon; suppression discipline; CI gating |
references/ci-and-release.md |
Cross-platform CI matrix, prebuilds (glibc/musl/arch), coverage, npm provenance, vendored-source supply chain |
references/modern-cpp-conventions.md |
RAII/ownership, rule of five, exception safety across the C ABI, concurrency correctness, header hygiene, maintainable structure |
Project adaptation
Treat the repository's build policy, documented toolchain floors, and platform constraints
as input — not automatic exemptions. Record accepted tradeoffs (a _FORTIFY_SOURCE=3
deferral because the prebuild container ships an older GCC, a deliberately single-writer
threading model) and their compensating controls explicitly, so future reviews do not
reopen the same decision without new facts.
1---2name: project-setup3description: Setup and hardening review for cross-platform modern-C++ (C++17) native projects, especially Node.js addons built with node-gyp / node-addon-api. Use when asked to "set up a native addon", "harden a C/C++ build", "review my binding.gyp", "add compiler hardening flags", "wire up AddressSanitizer/UBSan/TSan/clang-tidy", "set up cross-platform CI / prebuilds for a native module", or "make this native code maintainable". Produces an applicability-aware baseline gap analysis (Met / Gap / Not applicable / Needs verification) across build config, per-OS/per-arch compiler hardening, sanitizer & static-analysis wiring, CI/prebuilds/supply-chain, and modern-C++ conventions — not exploit findings.4---56# Native C/C++ Project Setup & Hardening78Assess a cross-platform modern-C++ (C++17) project — especially a Node.js native addon9built with node-gyp and node-addon-api — against a practical, evidence-based baseline for10build hardening, analysis tooling, portability, and maintainable code. Report applicable11preventive-control gaps even when no defect is currently proven, while clearly12distinguishing hardening advice from actual bugs.1314Use the **OpenSSF Compiler Options Hardening Guide** as the compiler/linker backbone, the15**C++ Core Guidelines** for code conventions, **CERT C/C++** and the sanitizer/tool docs16for analysis, and official node-gyp / Node-API documentation for the addon toolchain. See17[ATTRIBUTION.md](./ATTRIBUTION.md).1819## Boundary with resource review2021Keep this skill separate from `resource-review`:2223| This skill (`project-setup`) | The `resource-review` skill |24| ----------------------------------------------------- | --------------------------------------------- |25| Asks whether applicable controls meet a baseline | Asks whether a memory/resource defect exists |26| Reports evidence-backed best-practice gaps | Reports only proven defects |27| Uses Met / Gap / Not applicable / Needs verification | Uses Critical / High / Medium / Low |28| Prioritizes Essential / Recommended / Optional | Prioritizes impact and trigger reachability |2930A missing stack protector or an unset sanitizer job is a hardening Gap, not a31vulnerability. If the assessment uncovers an actual defect (a real leak, use-after-free,32or race), list it separately under **Escalate to resource review** and recommend33the `resource-review` skill; do not mix it into hardening counts or assign it a CVSS-style34severity.3536## Core rules3738- **Applicability before compliance.** Profile the project and select only controls that39 match its real build systems, target OSes/arches, threading, prebuild strategy, and40 vendored dependencies.41- **Effective behavior over presence.** A flag in one `conditions` branch, a sanitizer42 script that never runs in CI, or a `.clang-tidy` with `WarningsAsErrors: ''` is not43 proof the control is effective on the shipped build.44- **Research globally, report locally.** Read the whole `binding.gyp`/CMake, CI workflows,45 scripts, and `common.gypi` defaults to resolve what the compiler actually receives;46 report only on the requested scope.47- **Credit toolchain defaults.** Mark a control Met when the toolchain or node-gyp48 `common.gypi` already provides it (MSVC `/GS`, `/DYNAMICBASE`, `/NXCOMPAT` are on by49 default; Release builds optimize). Do not flag a default-on protection as missing.50- **Arch-gate the dangerous flags.** Some hardening flags **hard-error** on the wrong51 architecture (`-fcf-protection=full` is x86-only; `-mbranch-protection` is arm64-only).52 Recommending them ungated breaks the build — always require a `target_arch` condition.53- **No cargo-cult controls.** Record Not applicable when a control has no relevant surface54 (TSan on a strictly single-threaded synchronous addon; `-Wl,-z,*` on a macOS-only55 build), with one-line reasoning.56- **Sanitizer-aware.** `_FORTIFY_SOURCE` must be **off** in AddressSanitizer builds.57 Standard-library hardening assertions are independent and may remain enabled unless the58 project's exact toolchain demonstrates a conflict; a hardening recommendation that breaks59 the sanitizer build is a Gap, not an improvement.60- **No auto-apply.** Propose changes; edit only when the user explicitly asks.6162## Control states and priorities6364Every assessed control has exactly one state:6566| State | Meaning |67| --------------------- | ------------------------------------------------------------------------------ |68| **Met** | Effective implementation is evidenced in build config, CI, or toolchain default |69| **Gap** | Control applies and evidence shows it is absent, disabled, or materially incomplete |70| **Not applicable** | The project lacks the surface (no Windows target, no threads, no prebuilds, …) |71| **Needs verification**| The control applies, but a required fact (toolchain version, CI behavior) cannot be established statically |7273Prioritize gaps by risk reduction, not by fear:7475| Priority | Use when |76| --------------- | ------------------------------------------------------------------------------------------------- |77| **Essential** | A broadly expected boundary is missing on a security-sensitive surface: no stack protector/FORTIFY on code doing raw buffer/`memcpy` work; C++ exceptions able to cross the C ABI; mutable global state in a worker-capable addon; over-broad sanitizer suppressions masking first-party leaks |78| **Recommended** | Meaningful hardening with clear applicability: full RELRO (`-Wl,-z,relro -Wl,-z,now`), UBSan+TSan in CI, `-fvisibility=hidden` on C++ TUs, an oldest-glibc prebuild, arch-gated CFI |79| **Optional** | Context-dependent defense-in-depth or maturity: `-fstrict-flex-arrays=3`, `-ftrivial-auto-var-init=zero`, `-D_GLIBCXX_ASSERTIONS` in release, extra CI telemetry |8081Do not use priority as a disguised severity. Consider exposure (does untrusted input82reach the native code?), what the code actually does, existing compensating controls, and83implementation/toolchain cost.8485## Review workflow8687Run these steps in order. Load reference files only when their domains apply.8889### 1. Resolve scope9091- If the user names paths or a diff, report only on those while researching the rest of92 the build. Otherwise review working changes, including untracked files:93 ```bash94 if git rev-parse --verify --quiet origin/HEAD >/dev/null; then95 git diff --merge-base origin/HEAD96 else97 git diff HEAD98 fi99 git ls-files --others --exclude-standard100 ```101102### 2. Build the project profile103104Establish from config rather than assumptions (read105[`references/build-and-toolchain.md`](./references/build-and-toolchain.md)):106107- build system(s): node-gyp/`binding.gyp`, CMake, or both; node-addon-api and108 `NAPI_VERSION`; `NAPI_CPP_EXCEPTIONS`;109- language standard and how it is set per platform;110- target OSes (Linux glibc/musl, macOS, Windows) and arches (x64, arm64);111- prebuild strategy (prebuildify/node-gyp-build, prebuild) and shipped binaries;112- concurrency: worker threads, `AsyncWorker`, threadsafe functions, shared state;113- vendored C/C++ sources (amalgamations) and how they are pinned/updated;114- CI matrix, sanitizer/analysis jobs, and release/publish flow.115116State unresolved assumptions in the report.117118### 3. Select the baseline119120Read [`references/baseline-and-reporting.md`](./references/baseline-and-reporting.md). Pin121the compiler/linker baseline to the **OpenSSF Compiler Options Hardening Guide** and the122code baseline to the **C++ Core Guidelines**; verify version-sensitive flag availability123against the project's actual toolchain floor (for example the oldest glibc/GCC used by its124prebuild container). Never assert a flag exists without confirming it for that toolchain.125126### 4. Select applicable domains127128| Detected surface | Load |129| ------------------------------------------------------------ | -------------------------------------------------------- |130| Always | `baseline-and-reporting.md`, `build-and-toolchain.md` |131| Any compiled C/C++ (all real projects) | `compiler-hardening.md` |132| Any project that can build under a sanitizer / static analyzer | `sanitizers-and-analysis.md` |133| Ships prebuilt binaries, multi-OS/arch, vendors C sources | `ci-and-release.md` |134| Hand-written C++ (RAII, ownership, threading, C-ABI boundary) | `modern-cpp-conventions.md` |135136### 5. Gather evidence137138For each applicable control:139140- read the *effective* flags the compiler/linker receive for the Release build on each141 OS/arch, not just one `conditions` branch;142- confirm CI actually runs and *gates* on the control (a sanitizer job whose zero exit is143 never checked, or `clang-tidy` with `WarningsAsErrors: ''`, is advisory, not enforced);144- credit toolchain and `common.gypi` defaults; account for arch/OS applicability;145- record `file:line` evidence for Met and Gap; use Needs verification for a concrete146 missing fact (a toolchain version, whether a CI job blocks merge), phrased as a question.147148Presence of a flag in the file is a lead; effectiveness on the shipped build is the149finding.150151### 6. Consolidate152153Group repeated misses under the narrowest common remediation (one missing POSIX hardening154block covering every non-Windows TU is one Gap, not one per file). Separate controls when155OS/arch applicability or remediation differs.156157### 7. Report158159Use the structure in `baseline-and-reporting.md`:160161```markdown162## Native Setup & Hardening Review: <scope>163164**Project profile:** <build systems, targets/arches, prebuilds, threading, vendored deps>165**Baseline:** OpenSSF Compiler Hardening Guide + C++ Core Guidelines166**Assumptions:** <unresolved toolchain/CI facts>167168### Coverage Summary169| Domain | Met | Gap | Needs verification | Not applicable |170|--------|----:|----:|-------------------:|---------------:|171172### Essential Gaps173#### [HARDEN-001] <control> — Gap174- **Applicability:** Why this control applies to this project.175- **Evidence:** `file:line` and the effective build behavior observed.176- **Recommendation:** Minimal concrete change (arch-gated where required).177- **Tradeoffs:** Toolchain floor, startup cost, sanitizer-build interaction.178- **Source:** OpenSSF/Core Guidelines/vendor reference.179180### Recommended Gaps181...182### Optional Improvements183...184### Needs Verification185...186### Controls Already Met187### Not Applicable188### Remediation Roadmap1891. Now — Essential, low-risk, arch-gated fixes.1902. Next — Recommended controls and CI gating.1913. Later — Optional defense-in-depth.192193### Escalate to Resource Review194Only concrete defects, excluded from hardening counts — recommend the `resource-review` skill.195```196197If no gaps remain, say which profile/baseline was assessed and that all applicable198controls examined were Met; still list unresolved verification questions.199200## Source freshness201202Prefer primary sources in this order:2032041. OpenSSF Compiler Options Hardening Guide for the flag baseline.2052. Compiler/linker vendor docs (GCC, Clang/LLVM, Microsoft Learn) for exact flag behavior,206 arch applicability, and minimum toolchain version.2073. C++ Core Guidelines and cppreference for code conventions.2084. Sanitizer/tool docs (AddressSanitizer, clang-tidy, Valgrind) and node-gyp/Node-API209 docs for tooling and addon specifics.210211When internet access is available, verify version-sensitive flags against the project's212toolchain floor. Never use listicles as normative sources. When offline, use the pinned213references and state that current toolchain behavior was not re-verified.214215## References216217| File | Covers |218| ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------- |219| [`references/baseline-and-reporting.md`](./references/baseline-and-reporting.md) | Standards backbone, profile-driven applicability, evidence rules, state/priority calibration, report format |220| [`references/build-and-toolchain.md`](./references/build-and-toolchain.md) | `binding.gyp` anatomy, node-addon-api/`NAPI_VERSION`, standard selection, symbol visibility/prefixing, vendoring, Windows arch traps |221| [`references/compiler-hardening.md`](./references/compiler-hardening.md) | Per-OS/per-arch compiler & linker hardening flag matrix (GCC/Clang + MSVC), arch-gating, FORTIFY-vs-sanitizer, the `.node`-is-a-shared-library reality |222| [`references/sanitizers-and-analysis.md`](./references/sanitizers-and-analysis.md) | Wiring ASan/UBSan/TSan/LSan/Valgrind and clang-tidy/cppcheck; running them against a Node addon; suppression discipline; CI gating |223| [`references/ci-and-release.md`](./references/ci-and-release.md) | Cross-platform CI matrix, prebuilds (glibc/musl/arch), coverage, npm provenance, vendored-source supply chain |224| [`references/modern-cpp-conventions.md`](./references/modern-cpp-conventions.md) | RAII/ownership, rule of five, exception safety across the C ABI, concurrency correctness, header hygiene, maintainable structure |225226## Project adaptation227228Treat the repository's build policy, documented toolchain floors, and platform constraints229as input — not automatic exemptions. Record accepted tradeoffs (a `_FORTIFY_SOURCE=3`230deferral because the prebuild container ships an older GCC, a deliberately single-writer231threading model) and their compensating controls explicitly, so future reviews do not232reopen the same decision without new facts.