# Memory-safety pre-scan (C/C++)

- target: `sample-repo`
- source files scanned: 2
- findings: HIGH 13 · MEDIUM 9 · LOW 3 · INFO 0

_Deterministic pre-scan — not an audit. Line/window-based; no dataflow. A clean report is not proof of memory safety._


## HIGH

- `hostile/server.c:10` **MS-GETS** — `gets()` has no bound and no safe use — deleted from C11/C++14; replace with fgets
- `hostile/server.c:11` **MS-SCANF-NOWIDTH** — `scanf` %s/%[ conversion without a field width — unbounded write into the destination buffer; add a width (%31s) or use fgets
- `hostile/server.c:12` **MS-SCANF-NOWIDTH** — `fscanf` %s/%[ conversion without a field width — unbounded write into the destination buffer; add a width (%31s) or use fgets
- `hostile/server.c:17` **MS-STRCPY** — `strcpy` copies with no length argument into a fixed-size array (dst[16]) — use strlcpy/strncpy+terminate/snprintf
- `hostile/server.c:19` **MS-STRCPY** — `strcat` copies with no length argument into a fixed-size array (dst[16]) — use strlcpy/strncpy+terminate/snprintf
- `hostile/server.c:20` **MS-SPRINTF** — `sprintf` writes an unbounded formatted string into a fixed-size array (dst[16]) — use snprintf
- `hostile/server.c:22` **MS-COPY-LITOVER** — `memcpy` size 128 exceeds `dst[16]` — literal overrun
- `hostile/server.c:25` **MS-STRNCPY-NONUL** — `strncpy` bound taken from strlen(src) — bounded in name only; same exposure as strcpy/strcat
- `hostile/server.c:26` **MS-COPY-LITOVER** — `fgets` size 256 exceeds `dst[16]` — literal overrun
- `hostile/server.c:30` **MS-FMT-NONLIT** — `printf` format argument `req` is not a string literal — a `%`-bearing value becomes an arbitrary read/write primitive; pass "%s"
- `hostile/server.c:31` **MS-FMT-NONLIT** — `fprintf` format argument `req` is not a string literal — a `%`-bearing value becomes an arbitrary read/write primitive; pass "%s"
- `hostile/server.c:32` **MS-FMT-NONLIT** — `syslog` format argument `req` is not a string literal — a `%`-bearing value becomes an arbitrary read/write primitive; pass "%s"
- `hostile/server.c:39` **MS-RET-STACK** — `return tmp` hands the caller a pointer to a function-local array — dangling stack storage (CWE-562)

## MEDIUM

- `hostile/server.c:18` **MS-STRCPY** — `strcpy` copies with no length argument into a destination of unknown bound — use strlcpy/strncpy+terminate/snprintf
- `hostile/server.c:21` **MS-SPRINTF** — `vsprintf` writes an unbounded formatted string into a destination of unknown bound — use snprintf
- `hostile/server.c:23` **MS-MEMCPY-VARSZ** — `memcpy` into `dst[16]` with a non-literal size — no visible bound; clamp to sizeof(dst)
- `hostile/server.c:24` **MS-STRNCPY-NONUL** — `strncpy` into `dst[16]` can fill the buffer with no NUL terminator — add `dst[sizeof(dst)-1] = '\0'`
- `hostile/server.c:43` **MS-ALLOC-UNCHECKED** — `p = malloc(...)` is dereferenced with no NULL check in sight — NULL deref on OOM
- `hostile/server.c:44` **MS-STRCPY** — `strcpy` copies with no length argument into a destination of unknown bound — use strlcpy/strncpy+terminate/snprintf
- `hostile/server.c:48` **MS-DOUBLE-FREE** — second `free(p)` with no reassignment between calls — double-free / use-after-free risk
- `hostile/server.c:51` **MS-ALLOCA-VAR** — `alloca()` with a non-literal/large size — unbounded stack consumption
- `hostile/server.c:53` **MS-MKTEMP** — `mktemp()` returns a predictable name — race/ symlink-planting window; use mkstemp/ O_TMPFILE

## LOW

- `hostile/server.c:45` **MS-REALLOC-SELF** — `p = realloc(p, ...)` leaks the old block on failure — assign to a temp first
- `hostile/server.c:49` **MS-INT-ALLOC** — `malloc` size is a product of non-literals — integer overflow yields an undersized buffer (calloc-safe form: calloc(n, m))
- `hostile/server.c:54` **MS-BANNED-LOW** — `strtok()` is on banned-function lists — not reentrant; use strtok_r/strsep
