ponytail-sec

Security plugin for AI coding agents · open source

The smallest change that ruins an attacker's day.

A laser-focused security engineer sitting next to you while you code. It keeps your attack surface small: less code, fewer dependencies, tighter controls, and the one fix that breaks the attack chain.

  • /ponytail-secCompanion. Reviews the code you just wrote and tells you whether it's safe to ship.
  • /ponytail-sec-auditAudit. Scans the whole repo and rates every finding as a vulnerability or hardening.
  • /ponytail-sec-triageTriage. Proves, disproves or rescores each finding with evidence from your project.
> /plugin marketplace add andypitcher/ponytail-sec
> /plugin install ponytail-sec@ponytail-sec
ponytail-sec mascot: a man with a ponytail and glasses in a blue hard hat marked SeC

Companion · /ponytail-sec

Write code. Run /ponytail-sec. Ship with confidence.

It reviews only what you just wrote, so it stays fast and on point. You get a second pair of security eyes on every change instead of a backlog.

  1. Write codeBy hand or with your agent, as you normally would.
  2. Run /ponytail-secOr just say “harden this”, “security review” or “is this dep safe”.
  3. It reads what changedYour uncommitted diff, the commits on your branch, or the files you name. Never the whole repo.
  4. Three passes, up to 3 findingsEach finding comes with a fix and a break-risk: how likely that fix is to break something.
  5. One verdict, then fix and re-runFix with /ponytail and run it again until it says ship.
    Ship blocked. Fix before merging.Locked down. Ship.

Examples: a new service with 3 issues · a risky new dependency

> /ponytail-sec
  scope: diff vs main · 2 files · +42 lines

Pass 1 · Code
  C1  CheckManagerReachability() has no caller.
      Delete it, its init() and the token.  Break-risk: Low

Pass 2 · Dependencies
  No new dependencies. Clean.

Pass 3 · Security
  S1  vulnerability  1 · Trust  InsecureSkipVerify set
      on http.DefaultTransport           Break-risk: Medium
  S2  vulnerability  3 · Exec   ?target= concatenated
      into sh -c "ping -c 3 …"           Break-risk: Low

  kill-chain: 2 paths found.
  1 more material finding withheld. Type 'show all'.

Ship blocked on security. Fix before merging.

Real output, trimmed, from a run on a sample Go controller.

Three passes, in order

Every review asks the same three questions.

Companion and audit run the same passes, and each one shrinks your attack surface. Code that doesn't exist can't be attacked, so deleting comes first.

  1. Code

    Does this code need to exist at all?

    YAGNI, stdlib first, remove over refactor. Dead code and unrequested abstractions are security debt. Fewer lines, smaller attack surface.

    C1CheckManagerReachability() has no caller → delete it, its init() and the token
  2. Dependencies

    Does this dependency need to exist?

    Every dependency is supply-chain surface. Fewer dependencies, fewer ways in for a supply-chain attack. Each one is checked against its registry page and OpenSSF Scorecard: maintainer, last release, SECURITY.md.

    remove›stdlib›vendor or fork›immutable pin›keep floating

    D1gjson v1.14.0 → remove: only an unused package imports it
  3. Security

    Which one change breaks the kill chain?

    Walks four stages, top to bottom. A Stage 1 break voids every defence below it. Findings are ranked by attacker leverage removed ÷ lines changed, so the smallest fix that closes a path wins.

    1. 1 · TRUSTCan they forge or bypass identity?
    2. 2 · AUTHZIf they're in, can they escalate?
    3. 3 · EXECIf they execute, can they escape?
    4. 4 · DATAIf they're in, what do they reach?
    S23 · Exec · drop the shell
    - exec.Command("sh", "-c", "ping -c 3 "+target)+ exec.Command("ping", "-c", "3", "--", target)

Audit · /ponytail-sec-audit

The whole repo, when you need the full picture.

The same three passes across every source file, Dockerfile, manifest, config file and dependency. No cap on findings this time.

Run it
When you need the whole picture, not just one change. Or say “full security audit”.
It reads
The entire project. On large repos it starts with auth paths, TLS, shell exec, dependency resolvers and shipped config.
You get
Every finding rated as a vulnerability or hardening, a blast-radius summary, and a frank “if I were you” that can disagree with the scores.
Saved
report.md, findings.json and meta.json under .ponytail-sec/. Each scan is compared with the last: resolved, recurring or regression. Triage decisions carry over.
Ends with
An offer to triage the open findings: all, pick by number, or no.

Example: a full audit with persisted findings

> /ponytail-sec-audit

Pass 3 · Security
  #   Class          Rating                       Stage
  S1  Hardening      Efficacy: High               2 · Authz
  S2  Vulnerability  Severity: High (CVSS-B 8.7)  3 · Exec
  S3  Hardening      Efficacy: Medium             4 · Data

  kill-chain: 3 paths found.

  If I were you I'd start with S2: one line, and the
  only live execution path.

  Findings saved to .ponytail-sec/audit-20261031-230328-2E8tQ8/
  3 open findings (1 vulnerability, 2 hardening).
  Want me to run /ponytail-sec-triage on them?  all · S1 · no

Real output, trimmed, from the same sample repo.

Vulnerability or hardening

Hardening counts. It gets its own scale.

Much of what keeps an attacker out isn't a bug fix. It's a control that was missing or too loose. ponytail-sec reports those as first-class findings, and measures them by what the fix takes away from an attacker.

Vulnerability

Behaviour contradicts the documented contract: injection, auth bypass, privilege escalation, path traversal, a hardcoded secret. Something is broken.

Rated by severity and CVSS 4.0Severity: High (CVSS-B 8.7)

The audit scores the base metrics only (CVSS-B). Triage can rescore to CVSS-BT or CVSS-BTE when your project's context supports it.

Hardening

Behaviour matches the contract, but the permissive option is the default or a control is missing: an RBAC wildcard, an ungated debug endpoint, missing TLS.

Rated by efficacy and a CWEEfficacy: High · CWE-269

The CWE maps each hardening finding to a CIS, OWASP ASVS or STIG control.

Efficacy

How much attacker leverage the fix removes. It's a label on purpose, never a number: CVSS base scores are driven by impact, so a missing control would outrank a real break.

High
One setting closes a whole kill-chain stage for every deployment.
Medium
Closes a real path, but one that needs a precondition, or the fix is more than flipping a default.
Low
Defence in depth: the paths it closes are mostly closed elsewhere.

Every finding also carries a break-risk (Low, Medium or High): how likely the fix is to break something. It is separate from severity and efficacy.

Triage · /ponytail-sec-triage

Finding is easy. Triage is the hard part.

Any scanner can list problems. Triage decides which ones are real in your deployment and how bad they are, and proves it before anyone spends time on a fix.

  1. Context firstReads SECURITY.md, your threat model and manifests, checks published advisories, then asks up to 5 skippable questions.
  2. One evidence bundle per findingThe finding, its code with callers and callees, the context, your answers.
  3. A fresh, read-only agent judges itIt never sees the audit's narrative or ranking, so the audit can't grade itself.
  4. Only commands you approve runTests, grep, read-only kubectl. Every output is saved as evidence, and each finding gets its own <ID>.triage.md report.
  • No evidence, no verdict. affected needs an evidence file; otherwise it stays under_investigation.
  • Reclassifies both ways when the evidence says so, and asks first. Hardening becomes a vulnerability only with a cited source and a proof of concept.
  • Scored in isolation. Never invents a CVE. Proposes the fix and never applies it.

Examples: a triage walkthrough · hardening reclassified as a vulnerability

From a demo run

Same three findings, three different answers.

Sample repo built from the plugin's examples. The repo is fictional; the commands and their output are real.

S2

Vulnerability · audit: Severity High, CVSS-B 8.7

affectedCVSS-BTE 7.4

A proof-of-concept test ran a shell command through a job name. Rescored with context: the payload is public and tenant kubeconfigs are at stake.

S1

Hardening · audit: Efficacy High, CWE-269

affectedverification pending

No Go code reads Secrets, but a chart hook borrows the same ServiceAccount. Prove the fix on a cluster first.

S3

Hardening · audit: Efficacy Medium, CWE-1188

not_affectedEfficacy Low

The shipped binary doesn't contain the debug endpoint. Checked with go list -deps, not taken on trust.

Demo · 1:41

Watch all three run.

The developer's answers in the triage step are scripted for the demo.

Install

Two commands, then review your next change.

Runs in Claude Code and Antigravity CLI today. Cursor support is coming.

Latest

> /plugin marketplace add andypitcher/ponytail-sec
> /plugin install ponytail-sec@ponytail-sec

Pinned to a release

> /plugin marketplace add andypitcher/ponytail-sec@v0.2.6
> /plugin install ponytail-sec@ponytail-sec

Pick any tag from the version list in place of v0.2.6.