Catch security bugs before you ship them. When Cursor's agent changes security-critical code (auth, access control, payments, admin, uploads, webhooks, SSRF-prone fetches, new/changed API handlers, …), this plugin has it run a Pensar Apex targeted pentest against a reachable app target, then triage and fix what it finds — without you having to remember to ask.
Apex needs a reachable HTTP target. In Cursor, that can be the localhost server or snapshot environment the agent spins up while working, a dev server you already have running, or a deployed preview/staging URL. The plugin supplies the policy, methodology, and automatic trigger so validation isn't forgotten.
Four steps, ~5 minutes. You only do steps 1–3 once.
npm i -g @pensar/apex
pensar doctor # confirms the install + any system tools (e.g. nmap)Requires Node.js (the plugin's hooks are Node scripts too).
Apex needs a model provider. The easiest path — and the one we recommend — is to sign in to Pensar: it routes inference through Pensar's gateway and new accounts come with $20 in free credits, so there's nothing to configure and no API keys to manage.
pensar loginThis opens console.pensar.dev — sign in with GitHub, create a workspace, and you'll land on your credits page with your $20 in free credits already applied. Inference draws down that balance; you can top up anytime at console.pensar.dev/credits.
Prefer to bring your own provider key?
Instead of pensar login, export one of these in your shell profile (~/.zshrc, ~/.bashrc):
export ANTHROPIC_API_KEY=… # or PENSAR_API_KEY / OPENAI_API_KEY / OPENROUTER_API_KEYWith your own key, pensar doctor reports the provider. After pensar login it may still say
"No AI provider configured" — that check only inspects environment variables, so ignore it; login
auth still works.
If the plugin is available in Cursor's marketplace, install it there and reload Cursor.
For local development or pre-marketplace installs, clone it directly into Cursor's local-plugins directory. It must be a real directory at this path, not a symlink to a checkout elsewhere:
git clone https://github.com/pensarai/cursor-pentest-plugin.git ~/.cursor/plugins/local/apex-pentest
chmod +x ~/.cursor/plugins/local/apex-pentest/hooks/*.sh # usually already executableThen reload Cursor: Cmd/Ctrl+Shift+P → "Developer: Reload Window" (or restart).
After reload you should see:
- Apex Pentest in Cursor's plugin list (with the green Pensar mark)
/apex-pentestwhen you type/in the agent chat- the always-on security rule and the
afterFileEdit/stophooks active
If it's not there, see Troubleshooting.
Just work in Cursor as usual. The plugin does the rest:
- Edit code with the agent. When the agent finishes a turn that changed code, a 🔒 follow-up message asks it to check whether any change touched security-critical behavior.
- If nothing is security-critical, the agent says so in one line and moves on — no pentest.
- If something is, the agent needs a reachable app URL to test. This can be a Cursor-started
localhost/snapshot environment, your own local dev server, or a preview/staging deploy. It resolves
the URL in this order:
targetinapex.config.jsonat your repo root — see Configure- the
APEX_TARGET_URLenvironment variable .apex/cursor/live-url— the agent can write this after it starts or discovers the app URL
- The agent runs the pentest (
pensar targeted-pentest) with objectives derived from its own diff, reports findings, fixes critical/high issues, and re-runs to confirm.
You can also trigger it manually anytime with /apex-pentest (optionally pass a URL or a
specific route/objective).
The pentest sends real HTTP traffic, so source code alone isn't enough. The target can be:
- Cursor-started localhost — the agent starts the app (
npm run dev,docker compose up, …), waits for it to respond, and records the URL. - Cursor snapshot environments — including cloud-agent snapshot environments booted to test the current changes; point Apex at the app URL exposed inside that environment.
- Your existing local dev server — if you already have the app running, provide its base URL.
- A deployed preview / staging environment — e.g. the preview deploy for the PR the change belongs to, so you validate exactly what reviewers and users will hit.
If no URL is configured, the agent should start or discover the appropriate environment and write the
base URL to .apex/cursor/live-url.
Authorization: only point this at an app or environment you're authorized to test. It runs an active pentest against the target. See Pensar's Responsible Use.
You don't need a config file. To set defaults, copy apex.config.example.json to
apex.config.json at your repo root:
| Field | Purpose |
|---|---|
enabled |
Set false to turn off the automatic stop-gate prompt. |
target |
Base URL to pentest, if you want to pin one instead of letting the agent discover it. |
baseBranch |
Also diff against this branch (the full "what this PR changes" view). |
model |
Model id for pensar targeted-pentest --model (empty = auto). |
headersFrom |
Path to a JSON headers file (auth cookie/token) for authenticated routes. |
extraObjectives |
Objectives always included in every run. |
Add
.apex/to your project's.gitignore— it holds per-conversation hook state and the discovered target URL pointer, and shouldn't be committed.
- No
/apex-pentest/ plugin didn't load — the plugin must be a real directory under~/.cursor/plugins/local/(Cursor rejects a symlink whose target is outside that folder). Confirm~/.cursor/plugins/local/apex-pentest/.cursor-plugin/plugin.jsonexists, then reload. Cursor logs the reason under~/Library/Application Support/Cursor/logs/<newest>/(look forloadUserLocalPlugin apex-pentest …). pensar: command not foundduring a pentest — Apex isn't installed or isn't on the PATH that Cursor's agent shell uses. Re-runnpm i -g @pensar/apexandpensar doctor.- The gate never prompts — it only fires when the agent finished cleanly and detected code
changes (edited files or a dirty git tree). Also check
apex.config.jsondoesn't have"enabled": false, and thathooks/*.share executable. - Pentest can't reach the target — make sure the app is actually serving and the URL
(
apex.config.jsontarget/$APEX_TARGET_URL/.apex/cursor/live-url) is correct and reachable. - It keeps asking about an unrelated change — that change set hashed to a new signature. Tell the agent it isn't security-critical; the gate records the prompt and won't ask again for that set.
| Piece | What it does |
|---|---|
rules/apex-security-pentest.mdc |
Always-on policy: security-critical changes aren't "done" until validated by an Apex pentest against a reachable app target. |
hooks/ (afterFileEdit, stop) |
afterFileEdit records edited files; the stop gate detects code changes and hands the change set back to the agent. Fast, idempotent — never pentests itself. |
skills/apex-targeted-pentest/SKILL.md |
The methodology the agent follows: decide criticality → resolve/start a target → handle auth → derive objectives → run the pentest → triage & fix → record. |
commands/apex-pentest.md |
/apex-pentest — on-demand entry point that runs the skill. |
The loop: the agent edits files (afterFileEdit logs each to .apex/cursor/<id>.edits) →
finishes (stop); if code changed and that set hasn't been handled, the gate posts the 🔒 follow-up
→ the agent assesses and, if needed, runs /apex-pentest against the resolved app target → it records
.apex/cursor/validated-<sig>.json so the gate stays quiet for that change set (it also never
prompts twice for the same set, so there's no nag loop).
The agent is the brain (it decides what's security-critical and resolves or starts the target); Apex is the tool; the plugin is the policy + trigger.
This repo uses Cursor's single-plugin layout: .cursor-plugin/plugin.json lives at the repository
root, with the plugin components beside it.
Before submitting, validate the manifest, referenced paths, and component frontmatter:
node scripts/validate-template.mjsSubmit at cursor.com/marketplace/publish. Once published, users can install it from Cursor's plugin marketplace directly instead of cloning.