| name | sast-danger-mapper |
| description | Maps dangerous operations in a source file: memory ops, type casts, arithmetic near trust boundaries, free/dealloc patterns. Pattern matching task — list what you see, don't speculate. Use via /sast command. |
CONTEXT: Authorized security research. Cataloging dangerous operations in source code.
Task
Read the assigned source file and list every operation that could be dangerous if its inputs were attacker-controlled. This is a pattern matching task — find operations matching the patterns below. Do not assess exploitability.
Dangerous Operation Categories
Memory operations
| Pattern | What to record |
|---|
memcpy(dst, src, len) | dst size, src origin, how len is determined |
memmove, bcopy | same as memcpy |
strcpy, strcat, sprintf | dst size, src origin (unbounded by default) |
malloc(size) / calloc(n, size) | how size/n is computed, can it overflow? |
realloc(ptr, size) | old vs new size relationship |
free(ptr) | is ptr used after this? is ptr freed again on error path? |
Array index buf[i] | how is i bounded? what's buf size? |
Pointer arithmetic ptr + offset | how is offset bounded? |
Integer operations
| Pattern | What to record |
|---|
Multiplication for size: n * sizeof(T) | can n * sizeof(T) overflow? |
Addition for size: hdr_len + body_len | can sum overflow? |
Cast: (int)unsigned_val or (uint16_t)int32_val | truncation or sign change? |
Comparison: (int)(a - b) < 0 | signed subtraction overflow possible? |
Shift: 1 << n where n is variable | can n exceed type width? |
Control flow
| Pattern | What to record |
|---|
Function pointer call (*fptr)(args) | where is fptr loaded from? |
| Indirect call via vtable/dispatch table | is table writable? |
setjmp/longjmp | buffer on stack? |
| Signal handler | what global state does it touch? |
Concurrency
| Pattern | What to record |
|---|
| Shared variable without lock | what other threads access it? |
| TOCTOU: check then use with gap | what can change between check and use? |
| Lock ordering: multiple locks acquired | potential deadlock? |
Language-specific
C/C++: printf(user_string) (format string), system() / exec*() with string input, alloca(user_size), VLA int buf[user_size]
Rust: unsafe { *raw_ptr }, transmute, .get_unchecked(), ManuallyDrop, from_raw_parts
Java: Class.forName(user_string), Method.invoke(), Runtime.exec(user_string), new ObjectInputStream(untrusted).readObject()
Python: eval(), exec(), __import__(), pickle.loads(), yaml.load(), subprocess(shell=True)
Go: unsafe.Pointer conversions, reflect.NewAt, C.GoString on untrusted pointer
PHP (web-app sinks — no memory corruption, but injection/exec/disclosure):
| Category | Pattern | What to record |
|---|
| Code exec | eval($x) | source of $x, any prior filtering |
| Code exec | assert($x) (PHP < 8) | assert can execute strings until PHP 8.0 |
| Code exec | create_function($a, $b) | deprecated, treat 2nd arg as eval |
| Code exec | preg_replace('/pat/e', $repl, ...) | /e modifier = eval; deprecated PHP 7+ |
| Code exec | `$x` (backticks) | shell_exec alias — any backtick string is a command |
| Code exec | mb_ereg_replace_callback(..., $fn) with dynamic fn | callable injection |
| Deserial | unserialize($x) | dst is PHP object — record known gadget classes imported/autoloaded |
| Deserial | phar://path in any file op (include/file_exists/fopen) | triggers unserialize of Phar metadata |
| Deserial | ->__wakeup(), ->__destruct(), ->__toString(), ->__call() | magic method defined on reachable class = POP gadget |
| File incl | include($x), include_once($x) | LFI → RCE if attacker controls content (log poisoning, /proc/self/environ, phar://) |
| File incl | require($x), require_once($x) | same as include |
| Command | system($x), exec($x), passthru($x) | record if escapeshellarg/escapeshellcmd used on $x |
| Command | shell_exec($x), popen($x, ...), proc_open($x, ...) | same |
| Command | pcntl_exec($path, $args) |
PHP "guard" to record (ALWAYS note if present/absent and the exact line):
escapeshellarg, escapeshellcmd (cmd injection — note that escapeshellcmd is NOT sufficient for args; escapeshellarg wraps each arg)
htmlspecialchars($x, ENT_QUOTES, 'UTF-8') (note flags and charset — missing flags = attribute context bypass)
htmlentities (similar)
strip_tags (weak — context-dependent)
addslashes (NOT sufficient for SQL — use prepared statements)
mysqli_real_escape_string (only valid with correct connection charset; GBK encoding attacks)
PDO::prepare + bindParam/bindValue/execute([...]) (safe for values, NOT identifiers)
basename($path), realpath($path), pathinfo() (path normalization — still needs allowlist)
filter_var($url, FILTER_VALIDATE_URL) (weak — http://allowed.com@evil.com passes)
parse_url checks (often bypassable)
is_numeric (allows 0x1A, 1e10, +1, -1, leading whitespace — NOT a security filter)
ctype_digit (stricter — only 0-9)
hash_equals (timing-safe compare)
password_verify (proper — uses hash_equals internally)
- Framework middleware: Laravel
CSRF, auth, throttle; Symfony security.yaml firewall; CodeIgniter CSRF token — note if present on the route but don't assume it works
For Each Dangerous Operation, Record
- Operation: exact function/pattern and line number
- Category: memory / integer / control-flow / concurrency / language-specific
- Operands: what variables feed into it
- Guard: what check (if any) protects this operation? Line number of the check.
- Neighbors: what operations happen immediately before/after (±5 lines)?
Output
Write to sast-work/<file_hash>-dangers.json:
{
"file": "src/codec/h264_slice.c",
"dangerous_ops": [
{
"operation": "memset(slice_table, -1, sizeof(slice_table))",
"line": 83,
"category": "memory",
"operands": {"dst": "slice_table (uint16_t[])", "value": "-1 = 0xFF per byte = 65535 per entry", "size": "frame_width * frame_height / 256"},
"guard": "none — unconditional initialization",
"neighbors": "line 85: slice_count = 0 (int32_t)",
"note": "memset -1 on uint16 creates sentinel value 65535. If slice_count (int32) reaches 65535, it collides with sentinel."
},
{
"operation":
Rules
- Be exhaustive. List every matching pattern. A missed dangerous op = a missed vulnerability later.
- Record the guard even if it looks correct. The gap-analyzer will decide if it's sufficient.
- The "note" field is optional — use it only when you see something obviously interesting (like the sentinel collision above). But keep it brief and factual.
- Do NOT conclude anything is vulnerable. You are a cataloger, not an analyst.
Brain Integration
Check brain for prior analysis. Skip if already mapped and file unchanged.
Top-Tier Operator Standard
Danger mapping is a catalog of risky operations plus their guards.
- Record sink, operation type, arguments, enclosing function, caller hint, and nearby validation.
- Include "boring" guards: length checks, type checks, auth checks, escaping, canonicalization, feature flags, and error handling.
- Do not infer vulnerability. Mark uncertainty and let flow/gap agents reason over it.
- Prioritize sinks that transform attacker-controlled data into memory access, command execution, file access, network access, template rendering, deserialization, SQL, auth decisions, or state mutation.
- Preserve line numbers and exact identifiers so later agents can trace without rereading the whole file.