Skip to content

Binary hardening checks

These checks run against an ELF executable or shared object. Each section lists what the mitigation protects against, how checksec detects it, every value it can report (with color), and how to enable it.

See Understanding output for what the colors and Unknown / N/A mean. The key under each heading is the report key used in JSON/YAML output and with --fail-if.

Color shorthand used below

green · yellow · red · plain (info) · italic (N/A)


RELRO

Key: relro

Protects against: overwriting the GOT (Global Offset Table) and other runtime relocations to hijack control flow.

How checksec detects it: looks for a PT_GNU_RELRO segment (Partial) and a DT_BIND_NOW / DF_BIND_NOW flag in the dynamic section (Full). Any present DT_BIND_NOW entry counts as bind-now regardless of its value.

Value Color Meaning
Full RELRO green GOT is mapped read-only and bound at startup.
Partial RELRO yellow Some sections are read-only, but the GOT is still writable (lazy binding).
No RELRO red No RELRO protection.
N/A italic Not a dynamically-linked object.

Enable:

gcc -Wl,-z,relro,-z,now      # Full RELRO
gcc -Wl,-z,relro             # Partial RELRO only


Stack Canary

Key: canary

Protects against: stack-buffer-overflow attacks that overwrite the saved return address.

How checksec detects it: scans the symbol table for the stack-guard symbols __stack_chk_fail, __stack_chk_guard, or __intel_security_cookie.

Value Color Meaning
Canary Found green Stack-protector instrumentation is present.
No Canary Found red No stack canary.

Enable:

gcc -fstack-protector-strong   # recommended
gcc -fstack-protector-all      # every function (higher overhead)

Note

Stripped binaries can hide the symbol; checksec reports based on the symbols it can see. A binary with no vulnerable buffers may legitimately lack a canary even when the flag was passed.


CFI

Key: cfi

Protects against: control-flow hijacking (ROP/JOP) by enforcing forward-edge (indirect call) and backward-edge (return) control-flow integrity in hardware.

How checksec detects it: parses the .note.gnu.property GNU_PROPERTY_* bits, dispatched by architecture, and falls back to Clang-CFI symbol detection.

CFI is architecture-specific — the value names the relevant feature pair:

Arch Feature pair Both One Neither
x86 / x86-64 Shadow stack + IBT SHSTK & IBT (green) … & NO … (yellow) NO SHSTK & NO IBT (red)
ARM (aarch64) PAC + BTI PAC & BTI (green) … & NO … (yellow) NO PAC & NO BTI (red)
RISC-V Zicfilp + Zicfiss Zicfilp & Zicfiss (green) … & NO … (yellow) NO Zicfilp & NO Zicfiss (red)
Value Color Meaning
Unknown yellow No CFI properties found, or the architecture isn't recognized.

Enable:

gcc -fcf-protection=full                 # x86: shadow stack + IBT
gcc -mbranch-protection=standard         # ARM: PAC + BTI
gcc -fcf-protection -march=...zicfilp_zicfiss   # RISC-V


NX

Key: nx

Protects against: executing injected code from the stack or heap (W^X for data pages).

How checksec detects it: inspects the PT_GNU_STACK program header's permission flags.

Value Color Meaning
NX enabled green Stack is non-executable.
No GNU_STACK yellow No PT_GNU_STACK header — permissions are toolchain/loader-dependent.
NX disabled red Stack is executable (RWX).
N/A italic Not applicable to this object.

Enable: NX is the default. Avoid -z execstack; use -z noexecstack to be explicit. A No GNU_STACK result often means an assembly object didn't declare .note.GNU-stack.


PIE

Key: pie

Protects against: defeats ASLR bypasses by making the executable itself load-address-independent.

How checksec detects it: examines the ELF type (ET_DYN vs ET_EXEC), the DF_1_PIE flag, and the presence of a PT_INTERP segment.

Value Color Meaning
PIE Enabled green Position-independent executable.
Static PIE green Statically linked PIE (no interpreter).
DSO plain A shared library (.so) — PIE doesn't apply the same way.
REL yellow A relocatable object file (.o).
PIE Disabled red Fixed-load-address executable.

Enable:

gcc -fPIE -pie


RPATH

Key: rpath

Protects against: library-injection / hijacking via unsafe runtime library search paths baked into the binary (DT_RPATH).

How checksec detects it: reads DT_RPATH entries and classifies each path.

Value Color Meaning
No RPATH green No DT_RPATH set.
RPATH [path] plain Safe absolute path(s).
RPATH [path] ($ORIGIN) yellow Uses $ORIGIN or a nonexistent dir — context-dependent.
RPATH [path] (relative) red Relative, empty (cwd), or world-writable path — insecure.

Enable / remediate: prefer no rpath at all. If you must set one, use a trusted absolute path, and prefer RUNPATH over RPATH (-Wl,--enable-new-dtags).


RUNPATH

Key: runpath

Protects against: the same library-hijacking risk as RPATH, for the newer DT_RUNPATH entry (which is searched after LD_LIBRARY_PATH).

How checksec detects it: identical classification to RPATH, applied to DT_RUNPATH.

Value Color Meaning
No RUNPATH green No DT_RUNPATH set.
RUNPATH [path] plain Safe absolute path(s).
RUNPATH [path] ($ORIGIN) yellow $ORIGIN/nonexistent — context-dependent.
RUNPATH [path] (relative) red Relative/empty/world-writable — insecure.

Enable / remediate: same guidance as RPATH — ideally none, otherwise a trusted absolute path.


Symbols

Key: symbols

Protects against: information leakage — a fully populated symbol table makes reverse engineering and exploit development easier.

How checksec detects it: counts entries in the ELF symbol table.

Value Color Meaning
No Symbols green Stripped — no symbol table.
N symbols red N symbols are present (not stripped).

Enable (strip):

strip -s ./myapp        # strip an existing binary
gcc -s ...              # strip at link time


SafeStack

Key: safestack

Protects against: stack-based memory corruption by moving unsafe local buffers onto a separate, isolated "unsafe stack" (Clang SafeStack).

How checksec detects it: scans for the SafeStack runtime symbols.

Value Color Meaning
SafeStack Found green Compiled with SafeStack.
No SafeStack Found red SafeStack not present.

Enable:

clang -fsanitize=safe-stack


Stack Clash

Key: stack_clash

Protects against: "stack clash" attacks where a large stack allocation jumps the guard page into adjacent memory.

How checksec detects it: prefers authoritative annobin notes; if absent, falls back to a heuristic scan for the per-page stack-probe instruction pattern.

Value Color Meaning
Enabled green annobin notes confirm -fstack-clash-protection.
Likely Enabled green Heuristic found stack-probe instructions.
Disabled red annobin notes confirm it was not used.
No Probes yellow No annobin notes and no probes found — indeterminate.
Unknown yellow Could not classify.

Enable:

gcc -fstack-clash-protection


W^X segment

Key: separate_code

Protects against: having a single memory segment that is both writable and executable (W^X violation), which eases code injection.

How checksec detects it: verifies no PT_LOAD segment is simultaneously writable (PF_W) and executable (PF_X).

Value Color Meaning
Enabled green No writable+executable segment.
WX Segment red A segment is both writable and executable.
N/A italic No loadable segments (e.g. a relocatable .o).

Enable:

gcc -Wl,-z,separate-code     # default in modern GNU ld
ld.lld --rosegment           # LLVM lld


Selfrando

Key: selfrando

Protects against: function-level address leaks, by randomizing function layout at load time (the Selfrando project).

How checksec detects it: looks for the .txtrp section that Selfrando adds.

Value Color Meaning
Enabled green Selfrando instrumentation present.
No Selfrando plain Not present (the common case).

Note: Selfrando is a specialized, largely historical tool; most binaries will report No Selfrando, which is informational rather than bad.


Sanitizers

Key: sanitizers

Protects against: nothing in production — sanitizers are build-time bug-finding tools. checksec reports them so you don't accidentally ship a sanitizer-instrumented build.

How checksec detects it: scans for compiler-rt symbol prefixes (__asan_, __ubsan_handle_, __msan_, __tsan_, __lsan_).

Value Color Meaning
ASAN / UBSAN / MSAN / TSAN / LSAN (joined by +) plain The active sanitizer set.
None plain No sanitizers detected.

Note: a non-None result on a production binary is usually a packaging mistake — sanitizer builds are slower and expose internals. Build release artifacts without -fsanitize=....