CAP-PC ENS study materials
CAP-PC ENS study resources

CAP-PC ENS: Source-Code Analysis

CAP-PC ENS · Work through your exam, one topic at a time.

All guide sections

Source-Code Analysis

What this domain tests

Source-Code Analysis presents snippets, diffs or small repositories and asks where untrusted data lands, whether a sanitizer is sound, and which construct is actually dangerous. The skill under test is precise reading: taint path, guard placement, resolved dependency version.

Method

  • Map sources to sinks. Sources: request parameters, headers, cookies, uploaded files, database rows, queue messages, environment variables. Sinks: SQL builders, eval/exec, template rendering, filesystem paths, deserializers, XML parsers, redirects, loggers, HTTP clients.
  • Judge sanitizer soundness, not existence. Does it run on every branch? Is it applied to the same variable that reaches the sink? Does it match the target grammar? Check early returns and exception handlers that skip the guard.
  • Know the language-specific killers: Java ObjectInputStream and XStream, Python pickle and yaml.load versus yaml.safe_load, Ruby Marshal, PHP unserialize with type juggling, Node recursive merge causing prototype pollution, and path.resolve discarding earlier segments when a later segment is absolute.
  • Treat dependencies as resolved artifacts. A CVE matters only if the lockfile resolves the vulnerable version and the vulnerable function is reachable; manifests alone prove nothing.

Worked example

def download(name):
    p = os.path.join("/srv/files", name)
    if not os.path.realpath(p).startswith("/srv/files"):
        abort(403)
    return send_file(p)

name is user-controlled and reaches send_file. A guard exists, so the naive answer is no finding. The guard is unsound: a prefix comparison without a path separator accepts any sibling directory, so ../../files_backup/secret resolves to /srv/files_backup/secret, which passes startswith. The correct control compares against the base plus os.sep, or uses a common-path check, and rejects symlinks by resolving before comparison.

Traps that cost marks

  • Assuming one sanitizer call dominates every path through the function.
  • Confusing yaml.safe_load with yaml.load(..., Loader=FullLoader).
  • Reporting a CVE from a manifest line without checking the lockfile or reachability.
  • Missing second-order flows where data is stored safely and concatenated later.
  • Ignoring configuration and CI files when hunting hard-coded credentials.