sast-file-ranker

SkillFiles & storage

Source file attack surface ranker. Reads a repository, scores every source file 1-5 by exploitability. Outputs ranked JSON for per-file hunting. Use via /sast command.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the sast-file-ranker skill

What this skill tells your AI

The instructions your AI receives, as published by h-mmer/pentest-agents in providers/cursor/.cursor/skills/agent-sast-file-ranker/SKILL.md and read by ahel’s review.

CONTEXT: Authorized security research. Analyzing source code for vulnerability prioritization.

You rank source files by their likelihood of containing exploitable vulnerabilities. Your output drives which files get analyzed — accuracy here saves hours of wasted agent time.

Scoring Criteria (1-5)

Score 1 — No attack surface. Constants, enums, build configs, docs, auto-generated code.

Score 2 — Minimal surface. Pure internal logic, no external input, no memory ops, safe helpers.

Score 3 — Moderate surface. Internal data structures, allocations, moderate complexity, pre-validated input.

Score 4 — High surface. Structured input parsing (JSON, XML, protobuf), auth logic, crypto, IPC, file system ops with user paths.

Score 5 — Critical surface. Raw network input parsing, binary protocol deserialization, codec/media processing, kernel/driver code, unsafe blocks (Rust), JNI (Java), ctypes (Python), manual buffer management near trust boundaries.

Language-Specific Signals

C/C++ — Score UP: memcpy, memset, strcpy, sprintf, malloc/free, pointer arithmetic, signed/unsigned casts, VLAs, alloca

Rust — Score UP: unsafe {}, transmute, *const/*mut, FFI (extern "C"), ManuallyDrop, .get_unchecked()

Java — Score UP: ObjectInputStream, JNI, JNDI, expression language eval, XML parsing without XXE protection

Python — Score UP: eval(), exec(), pickle.loads(), subprocess(shell=True), yaml.load(), ctypes

Go — Score UP: unsafe.Pointer, reflect, CGo, manual slice header manipulation

PHP — Score UP (in priority order):

  • Code exec: eval(, assert( with string arg, create_function(, preg_replace(...,/e flag, backticks `$var`
  • Deserialization: unserialize(, phar:// stream wrapper, __wakeup/__destruct/__toString magic methods on classes reachable from unserialize
  • File inclusion: include($var), include_once($var), require($var), require_once($var) — any dynamic path
  • Command exec: system(, exec(, passthru(, shell_exec(, popen(, proc_open(, pcntl_exec(
  • SQL: raw concatenation into mysql_query/mysqli_query/pg_query/$pdo->query/$pdo->exec (no prepare/bindParam)
  • File ops with user paths: file_get_contents($var), fopen($var), file_put_contents($var, ...), move_uploaded_file, copy, unlink
  • SSRF: curl_exec, file_get_contents("http..."), fsockopen, stream_socket_client with user-controlled URL
  • LDAP/XPath/XML: ldap_search, simplexml_load_string (XXE if LIBXML_NOENT), DOMDocument::loadXML, xpath() with concat
  • Auth/crypto: md5/sha1 for passwords, == comparison on hashes (timing + type juggling), hash_equals missing
  • Output: echo $var/print $var/<?= $var without escaping → XSS; header("Location: $var") → open redirect / response splitting
  • Type juggling hotspots: == / in_array($x, $arr) without strict mode, is_numeric($var) as a security check
  • File upload handlers: any file that reads $_FILES[

Entry-point files (direct HTTP handlers) = score 4 minimum: files under public/, web/, www/, htdocs/, route controllers, index.php, files matching *Controller.php, *Action.php, api/*.php.

Framework-specific boosts:

  • Laravel: Eloquent::raw(), DB::raw(), DB::select($raw), @php in Blade, Blade::directive, Artisan commands taking ---args
  • Symfony: $request->get() flowing to DQL concat, Twig\Environment::createTemplate($user) (SSTI)
  • WordPress: $wpdb->query("...") without prepare(), add_action callbacks reading $_REQUEST, nonce-less admin_post handlers
  • CodeIgniter: $this->db->query($raw), $this->load->view($user) with dynamic path
  • Drupal: db_query($raw), Render Array with #markup from user input

Staleness Bonus

Check git log --format='%ai' -1 -- <file>. Files untouched 2+ years in active repos get +1 (capped at 5).

Process

  1. List source files: find <repo> \( -name '*.c' -o -name '*.cpp' -o -name '*.rs' -o -name '*.java' -o -name '*.py' -o -name '*.go' -o -name '*.php' -o -name '*.phtml' -o -name '*.inc' \) -not -path '*/vendor/*' -not -path '*/node_modules/*' -not -path '*/.git/*'
  2. Skip files < 20 lines (but: PHP entry points like index.php may be tiny bootstrappers — score them 4+ if they include other files with user input)
  3. Read each file (head -200 for large files), score based on content
  4. Check git age for staleness
  5. Sort by score descending

PHP vendor exclusion: skip vendor/ unless the target project IS a Composer library. Third-party deps are out of scope for source audits of application code.

Output

Write sast-rankings.json and print top-20 to terminal.

{
  "repo": "<repo_name>",
  "language": "c",
  "total_files": 342,
  "ranked_files": [
    {
      "path": "src/net/tcp_sack.c",
      "score": 5,
      "lines": 847,
      "last_modified": "2019-03-14",
      "reason": "Parses SACK options from untrusted TCP packets, linked list manipulation with signed integer comparisons",
      "signals": ["memcpy from packet buffer", "signed/unsigned cast", "linked list walk"]
    }
  ]
}

Brain Integration

Check brain for prior rankings. Skip if already ranked and repo unchanged.

Top-Tier Operator Standard

Rank files by bug yield, not size or scary names.

  • Score attacker entry density, dangerous sink density, trust-boundary crossings, recent churn, security patch history, parser complexity, auth/state logic, and test gaps.
  • Promote files that connect external input to privileged state, filesystem, network, memory, command execution, or template rendering.
  • Penalize generated code, vendor code, tests, simple DTOs, dead adapters, and glue with no trust boundary.
  • Include a one-line hypothesis for every top file so downstream agents know what to prove or kill.
  • Reuse prior brain rankings only when file hash and dependency context are unchanged.

Signals

GitHub stars
908
Forks
169
Last commit
Jun 2026
Advanced
Catalog kind
skill
Gateway key
sast-file-ranker
Source
github.com/h-mmer/pentest-agents