Work on this exercise locally

This web app is a reference guide — you can read instructions, browse starter code, and view tests here. To actually complete the exercise, you need to work in your local development environment.

1Clone the repo: git clone https://github.com/weihaoqu/program-analysis-bootcamp-student
2Edit the starter file in your editor (VS Code, Vim, etc.) — replace failwith "TODO" with your implementation.
3Run the tests: dune runtest modules/module5-security-analysis/exercises/vulnerability-detection

Vulnerability Detection

7. Exercise 5: Vulnerability Detection (18 tests)

Goal: Combine taint propagation with a security configuration to detect OWASP vulnerability patterns -- SQL injection, XSS, command injection, path traversal, and open redirect.

Time: ~30 minutes

File to edit: exercises/vulnerability-detection/starter/vuln_detector.ml

Also provided (read-only):

  • exercises/vulnerability-detection/starter/taint_domain.ml -- fully implemented
  • exercises/vulnerability-detection/starter/vuln_config.ml -- security config with default_config, is_source, find_sink, find_sanitizer
  • exercises/vulnerability-detection/starter/sample_programs.ml -- test programs

Dependencies: abstract_domains, shared_ast

Architecture

vuln_config.ml (provided)       vuln_detector.ml (YOUR CODE)
+---------------------------+   +------------------------------------+
| default_config            |   | eval_expr : config -> Env.t        |
| is_source, find_sink,     |   |           -> expr -> taint         |
| find_sanitizer            |   |                                    |
+---------------------------+   | check_call : config -> Env.t       |
                                |            -> ... -> vulnerability  |
taint_domain.ml (provided)      |              list                  |
+---------------------------+   |                                    |
| Bot/Untainted/Tainted/Top |   | transfer_and_check : config -> ... |
| join, propagate, ...      |   |   -> Env.t * vulnerability list    |
+---------------------------+   |                                    |
                                | analyze_function, analyze_program  |
sample_programs.ml (provided)   | format_vulnerability               |
+---------------------------+   | severity_of_vuln_type              |
| sql_injection, xss_       |   +------------------------------------+
| reflected, command_        |
| injection, ...            |
+---------------------------+

The vulnerability record

type vulnerability = {
  vuln_type : string;      (* e.g. "sql-injection" *)
  location : string;       (* function name *)
  source_var : string;     (* the tainted variable *)
  sink_name : string;      (* the sink function called *)
  message : string;        (* human-readable description *)
}

What to implement (in order)

#FunctionHint
1severity_of_vuln_type vt"sql-injection", "command-injection" -> Critical; "xss", "path-traversal" -> High; "open-redirect" -> Medium; other -> Low
2string_of_severity sCritical -> "CRITICAL", High -> "HIGH", Medium -> "MEDIUM", Low -> "LOW"
3eval_expr config env eLike Exercise 3, but use Vuln_config.is_source config, Vuln_config.find_sanitizer config, etc. instead of hardcoded lists
4check_call config env func_name call_name argsIf call_name is a sink, evaluate the argument at sink_param_index -- if potentially tainted, create a vulnerability record
5transfer_and_check config func_name env sTransfer the statement (updating env) AND check any Call expressions for vulnerabilities. Return (updated_env, vulnerabilities)
6analyze_function config funcInitialize params to Top, fold transfer_and_check over body, collect all vulnerabilities
7analyze_program config progMap analyze_function over all functions, concatenate vulnerabilities
8format_vulnerability vMust include the severity string (e.g. "CRITICAL") -- the test checks for it

Run tests

dune runtest modules/module5-security-analysis/exercises/vulnerability-detection/

Starter output (before any implementation):

EEEEEEEEEEEEEEEEEE

All 18 tests error. Start with the simple helper functions (severity_of_vuln_type, string_of_severity), then eval_expr, then build up from there.

Hints

  • check_call: Use Vuln_config.find_sink config call_name. If it returns Some sink, evaluate the argument at index sink.sink_param_index. If the taint is potentially tainted (Taint_domain.is_potentially_tainted), return a vulnerability. If the argument index is out of range or the call is not a sink, return [].

  • transfer_and_check: For an Assign(x, e) where e is Call(name, args), you need to both update the environment AND check the call. For If and While, recurse into branches and collect vulnerabilities from both.

  • format_vulnerability: The test checks that the output contains_substring "CRITICAL" for a sql-injection vulnerability. Make sure severity_of_vuln_type and string_of_severity work correctly first.