Safe Penetration Testing Labs · beginner · ~12 min

Generate a Markdown finding report

Take a `finding` struct and render it as a Markdown report section.

Overview

snprintf into a bounded buffer with ## title / **Severity:** ... / ### Evidence / ... / ### Recommendation / .... Reject buffers that would overflow.

Lesson

Why this matters

The hardest part of any security engagement is the writeup. A clean Markdown template — title, severity, affected asset, evidence, recommendation — is what turns notes into a deliverable.

This exercise teaches the formatter side: given a struct, produce the Markdown a human can read.

What the struct looks like

typedef struct {
    const char *title;         // "Missing HSTS header"
    const char *severity;      // "Low", "Medium", "High"
    const char *asset;         // "https://example.com/"
    const char *evidence;      // "Response missing 'Strict-Transport-Security'"
    const char *recommendation;// "Add HSTS with max-age >= 31536000"
} finding_t;

Your job

Implement int render_finding(const finding_t *f, char *out, size_t cap) that writes the Markdown into out (capped at cap-1 bytes + NUL). Return the number of bytes written, or -1 if the buffer would overflow.

Expected format

## Missing HSTS header
**Severity:** Medium
**Asset:** https://example.com/

### Evidence
Response missing 'Strict-Transport-Security'

### Recommendation
Add HSTS with max-age >= 31536000

Common mistakes

  • Using sprintf without checking the length. Use snprintf and the return-value-vs-cap check.
  • Missing the blank line between sections. Markdown renderers care.
  • Forgetting NUL-termination on a too-small buffer.

Summary

Strings in, Markdown out. Use snprintf with a bounded buffer; check both branches of its return value.

Practice with these exercises