Safeguard
Application Security•

What belongs on a secure coding checklist for C and C++ teams?

A practical C and C++ checklist built on OpenSSF compiler hardening options, CERT C rules and review habits. Learn which flags to use and what to check.

Safeguard Security Team
4 min read

A useful C and C++ checklist has three layers: compiler and linker hardening, coding rules that remove classes of bugs, and review habits that catch what tools miss. OpenSSF publishes a recommended set of GCC and Clang options, and the SEI CERT C standard supplies the rules.

Which compiler options should every build use?

The OpenSSF Compiler Options Hardening Guide for C and C++ gives a baseline for GCC and Clang. Its recommended set includes warnings, run-time protections and linker settings. Taken from the guide:

-O2 -Wall -Wformat -Wformat=2 -Wconversion
-Wimplicit-fallthrough -Werror=format-security
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
-D_GLIBCXX_ASSERTIONS
-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST
-fstrict-flex-arrays=3
-fstack-clash-protection -fstack-protector-strong
-Wl,-z,nodlopen -Wl,-z,noexecstack
-Wl,-z,relro -Wl,-z,now
-Wl,--as-needed -Wl,--no-copy-dt-needed-entries

The guide's table explains each. Fortify source adds compile-time and run-time checks for unsafe libc use and buffer overflows. The libstdc++ assertions add precondition checks on standard library calls. Both can cost performance. The linker flags mark the stack non-executable and make relocation entries read-only after load, and the now flag can affect startup time.

The guide adds options for specific situations: position-independent executables for programs, position-independent code for shared libraries, control-flow protection on x86_64 and branch protection on aarch64, and for C code, treating obsolete constructs as errors. Check your compiler version against the support table before adding a flag, since support differs between compilers.

Which coding rules matter most?

SEI CERT C is a set of rules and recommendations for secure C. Use it as the source for a team standard rather than inventing one. In review, focus on the families behind most memory bugs:

  • Integers. Check ranges before arithmetic that feeds a size, index or allocation. Conversion warnings help but do not replace checks.
  • Arrays and strings. Track the size alongside every buffer. Prefer length-aware functions, and confirm terminators.
  • Memory. One owner per allocation, no use after free, no double free, and clear sensitive buffers deliberately.
  • Format strings. Never pass external data as the format argument. The format-security error flag catches many cases.
  • Input. Treat anything from a file, socket or environment as untrusted until validated.

Constructed example: a function copies a name into a 32 byte buffer after checking that length is less than or equal to 32 but forgets the terminator. The compiler hardening flags may catch the overflow at run time as an abort. A reviewer who knows the rule catches it before it ships.

How do you review for these?

Ask three questions on every pointer and buffer. Where does the size come from? What happens at zero, at the maximum, and one past it? Who frees this, and can anyone touch it afterwards? Add a fourth for threaded code: what shared state is touched without a lock?

Run sanitizers (address and undefined behaviour) in your test builds and fuzz parsers. These are runtime tools and find bugs a checklist cannot.

What to do

  1. Adopt the OpenSSF baseline flags in your build files, and record which you excluded and why.
  2. Fail the build on format-security and implicit declaration warnings.
  3. Choose a rule set (SEI CERT C for C) and publish it as your team standard.
  4. Add the review questions above to your pull request template.
  5. Run address and undefined behaviour sanitizers in CI on the test suite.
  6. Fuzz every parser and protocol handler.
  7. Keep a list of third-party libraries with versions, and track their advisories.
  8. Verify the final binary has the protections you expect, for example by checking for PIE and relro.

Safeguard SBOM and dependency scanning can list the third-party C and C++ libraries you build against, and reachability analysis can help rank findings. It does not replace compiler hardening.

Quick check

Do hardening flags make C code safe?

No. They raise the cost of exploitation and turn some bugs into crashes. The bugs remain, so keep the coding rules and review.

Will these flags slow my program?

Some can. The OpenSSF guide notes that fortification, library assertions and the now flag can affect performance or startup, so measure before enabling everywhere.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.