MCPInstall

reviewing-security

Use when reviewing code for security before merging or shipping, and when a change touches untrusted input, authentication, authorization, secrets, SQL, subprocess execution, file paths, outbound requests, deserialization, uploads, or third-party dependencies. Triggers include "security review", "is this safe", "can this be exploited", "audit this for vulnerabilities", and adding any new external interface — an endpoint, a webhook, a plugin, or a tool an LLM can call.

Installs
146
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/osmontero/opencode-skills --skill reviewing-security
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads reviewing-security automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

Reviewing Security

Overview

Most security review output is worthless because it names categories instead of paths. "Validate all user input" is true of every program ever written and changes nothing. A useful finding is a path: an input an attacker controls, the code that carries it, the operation it reaches, and what the attacker gets.

Core principle: Follow the data, not a checklist. Vulnerabilities live in the gap between where a value enters and where it acts.

Companion skills: requesting-code-review for the general review loop, systematic-debugging when confirming an exploit path.

The Iron Law

NO FINDING WITHOUT A PATH FROM ATTACKER-CONTROLLED INPUT TO IMPACT

If you cannot name the input, the route it takes, and what it costs the operator, you have a code smell — file it under Observations, not Findings. Padding a report with categorical advice buries the one path that is real.

The corollary: trace the path in the actual code before reporting it. A grep hit is a lead, not a finding.

Checklist

  1. Map the attack surface — entry points, who reaches them, what privilege they run with
  2. Trace inputs to sinks — injection in all its forms
  3. Authorization — the highest-yield pass
  4. Secrets and crypto
  5. Process and plugin boundaries
  6. Dependencies
  7. Data exposure — logs, errors, responses
  8. Run the scanners — then verify reachability before reporting
  9. Report — severity by exploitability, each with a path

Step 1: Map the Attack Surface

Do this before reading implementation. You are building the list of places a stranger can reach.

Entry pointWho can reach itPrivilege it runs with
HTTP route, gRPC methodanon / authed / admin / internal-onlyprocess, DB role, filesystem
Queue or event consumerwhoever can publishusually full process
File upload, importany authed userparser runs in-process
Webhook receiverthe internet, until signature is verified
CLI flags, env, configlocal operator
LLM / tool outputanyone who can influence the model's contextwhatever the tool can do
# Enumerate handlers and consumers — adapt the pattern to the framework
grep -rnE '\.(Get|Post|Put|Patch|Delete|Handle|HandleFunc)\(' --include='*.go' --include='*.ts'
grep -rnE 'func \(.*\) [A-Z][A-Za-z]*\(ctx context.Context' --include='*.go'   # gRPC impls

That last row is not a novelty. Model output is untrusted input. If a document, a web page, or a prior tool result can steer the model into calling a tool, then every sink that tool reaches is attacker-reachable. Review tool definitions with the same suspicion as HTTP handlers.

Step 2: Trace Inputs to Sinks

For each entry point, follow the value. A sink is any operation whose behavior changes if the value is hostile.

SinkWhat makes it dangerousThe safe form
SQL / query builderstring concatenation or interpolationparameterized query; allowlist for identifiers, which cannot be parameterized
Shell / process spawna shell interpreter, or user data in argv[0]exec with an argv array, no shell, fixed binary path
Filesystem path.., absolute paths, symlinks, NULjoin, then filepath.EvalSymlinks, then verify the result is still under the root
Outbound HTTPuser-supplied URL → SSRFallowlist hosts; block private, link-local, and metadata ranges; re-check after redirects
Template renderautoescape off, or dangerouslySetInnerHTMLescaped by default; sanitize HTML with a real sanitizer
Deserializationpolymorphic or type-carrying formatsfixed schema, decode into a concrete type, cap size and depth
Archive extractionzip-slip, symlinks, decompression bombsvalidate each entry path, cap total bytes and entry count
Redirect targetopen redirect → phishing, token theftallowlist paths, or same-origin only
Regex over user inputcatastrophic backtrackingbound input length, avoid nested quantifiers
eval / reflection / dynamic importarbitrary codethere is no safe form — remove it

Follow the value across boundaries. The common miss is a value that is validated at the edge, stored, and then read back and trusted. Storage is not sanitization. If it is rendered or executed later, it is still tainted.

Concrete vulnerable/fixed pairs for each row: see references/vulnerability-patterns.md.

Step 3: Authorization

This is where the real bugs are. Injection is well-defended by modern libraries; broken object-level authorization is not, because it cannot be fixed by a framework — it requires knowing which rows belong to whom.

  • Every handler taking an ID verifies the caller may access that object — not merely that they are logged in
  • The check is on the path the data actually takes; a check in the route layer that the service layer can bypass is not a check
  • Tenant/org scoping is in the query (WHERE tenant_id = ?), not applied to results after fetching
  • No role, tenant, price, or user ID is trusted from the request body — mass assignment is authorization bypass with extra steps
  • Default deny: a new route without an explicit policy is unreachable, not public
  • State-changing operations are not reachable by GET
  • Sequential IDs are not the only thing standing between a user and someone else's record
  • Admin surfaces are gated by more than an unlinked URL
  • Authorization is re-checked on each step of multi-step flows, not only at the start
# Handlers that take an identifier — each one needs an ownership check
grep -rnE 'Param\("id"\)|params\.id|req\.body\.(userId|tenantId|role)' --include='*.go' --include='*.ts'

Step 4: Secrets and Crypto

  • No secret in source, config committed to git, logs, error messages, URLs, or client-visible bundles
  • No secret in git history — rotate anything ever committed; deleting it in a later commit fixes nothing
  • Passwords hashed with argon2id/scrypt/bcrypt — never a bare SHA, never unsalted
  • Tokens and signatures compared with a constant-time function
  • Randomness for tokens, IDs, and salts comes from a CSPRNG (crypto/rand, crypto.randomUUID) — never math/rand
  • JWTs: signature verified, algorithm pinned (reject none and algorithm confusion), exp/aud/iss checked
  • TLS verification never disabled — no InsecureSkipVerify: true, no NODE_TLS_REJECT_UNAUTHORIZED=0
  • Session tokens rotate on privilege change; logout invalidates server-side
  • Cookies: HttpOnly, Secure, SameSite set deliberately
  • No hand-rolled crypto primitives or custom "encryption"
gitleaks detect --no-banner          # or: trufflehog git file://.
git log -p -S'BEGIN PRIVATE KEY' --oneline | head

Step 5: Process and Plugin Boundaries

For anything that spawns a subprocess, loads a plugin, or executes tools on behalf of a model:

  • The child inherits only the environment it needs — not the full parent env with every credential in it
  • Working directory, open file descriptors, and network access are deliberate, not inherited by default
  • Child output is parsed as data, never re-entered as trusted instructions
  • Resource limits exist: timeout, memory, output size. An unbounded child is a denial-of-service primitive
  • Failure is closed — a crashed or unresponsive plugin denies the operation rather than skipping the check
  • The tool surface itself is the security boundary: a tool that takes a path, a URL, or a command is that sink, exposed to whoever influences the model

Step 6: Dependencies

  • Lockfile committed and honored in the build (npm ci, go mod verify)
  • Advisory scan clean, or each exception justified in writing with a reachability argument
  • New direct dependencies: check age, maintenance, download counts, and name against typosquats
  • Install/postinstall scripts reviewed for any new dependency
  • CI actions pinned to a SHA, not a moving tag
govulncheck ./...          # Go — reports only vulnerabilities you actually reach
npm audit --omit=dev       # Node
pip-audit                  # Python

govulncheck is worth more than a generic scanner precisely because it does reachability analysis. Prefer tools that tell you whether the vulnerable function is called.

Step 7: Data Exposure

  • Errors returned to clients carry no stack traces, SQL, file paths, or internal hostnames
  • Logs contain no passwords, tokens, session IDs, full card numbers, or PII beyond what is needed
  • Debug endpoints (/debug/pprof, GraphQL introspection, admin consoles) are disabled or gated in production
  • CORS: no Access-Control-Allow-Origin: * combined with credentials; the origin allowlist is explicit
  • Authenticated responses are not cacheable by shared caches
  • Object storage buckets and their listings are private by default
  • Timing and error-message differences do not reveal whether an account exists

Step 8: Run the Scanners, Then Verify

semgrep --config=auto .

Scanner output is a lead list, not a report. Before reporting any scanner hit, confirm it is reachable in this codebase — check whether the sink is actually called with a tainted value. Forwarding raw tool output is how a review becomes noise that gets ignored, taking the real findings with it.

Severity

Grade by exploitability, not by category name.

SeverityDefinition
CriticalUnauthenticated attacker gains code execution, credentials, or bulk access to other users' data. No unusual preconditions.
HighAuthenticated attacker escalates privilege, reads or writes another tenant's data, or extracts secrets.
MediumRequires an unusual precondition (a specific race, a chained bug, a user action) or yields limited data.
LowHardening. Real weakness, no demonstrated path today — a missing defense-in-depth layer that would contain a future bug.

Do not inflate. A report where everything is Critical is a report nobody acts on.

Report Format

## Scope
[What was reviewed — diff range, paths, or "full repo". What was NOT reviewed.]
[Scanners run and their versions.]

## Critical
**Tenant isolation missing on document fetch**
`internal/api/documents.go:88` — the handler loads by primary key only:
`db.First(&doc, c.Param("id"))`. There is no `tenant_id` predicate and no
post-fetch ownership check.
**Path:** any authenticated user → `GET /api/documents/{id}` → sequential
integer IDs → full document body of any tenant.
**Impact:** cross-tenant read of all documents; IDs are enumerable.
**Fix:** scope the query — `db.Where("tenant_id = ?", claims.TenantID).First(&doc, id)`
— and add the predicate at the repository layer so new callers inherit it.

## High
[same shape]

## Medium / Low
[same shape]

## Observations (not findings)
[Weaknesses with no demonstrated path. Say so plainly rather than promoting them.]

## Verified Clean
[What you checked and found sound. Silence reads as "not checked".]

## Assessment
**Ship?** Yes / No / After the Critical and High items
**Reasoning:** [1-2 sentences]

What NOT to Report

Do not reportWhy
"Add input validation" with no sinkCategorical advice, not a finding
Missing rate limiting with no abusable endpoint namedName the endpoint and the cost, or drop it
Missing browser security headers on a service with no browser clientThreat does not apply
Findings in tests, fixtures, or example codeNot attacker-reachable
Scanner output you did not confirm is reachableNoise that buries real findings
Cryptographic preference nits with no threat"Use AES-256 instead of AES-128" is not a finding
Anything you would describe as "theoretically"If it were exploitable you would have the path

Common Mistakes

Checklist review instead of path review. Walking OWASP Top 10 top to bottom finds the vulnerabilities that are already handled by the framework and misses the authorization bug that is unique to this domain.

Stopping at the entry point. Validation at the edge tells you nothing if the value is stored and later concatenated into a query.

Trusting the framework blindly. ORMs have raw-query escape hatches, templates have raw-output escape hatches, and both get used. Grep for them specifically.

Treating authenticated as authorized. The single most common real-world finding, and the easiest to miss by reading the route table instead of the query.

Reporting the model as trusted. If a tool call can be influenced by content the model read, its arguments are attacker-controlled.

Severity inflation to seem thorough. It costs you the reader's attention on the finding that matters.

FAQ

What does the reviewing-security skill do?

Use when reviewing code for security before merging or shipping, and when a change touches untrusted input, authentication, authorization, secrets, SQL, subprocess execution, file paths, outbound requests, deserialization, uploads, or third-party dependencies. Triggers include "security review", "is this safe", "can this be exploited", "audit this for vulnerabilities", and adding any new external interface — an endpoint, a webhook, a plugin, or a tool an LLM can call.

How do I install reviewing-security?

Run npx skills add https://github.com/osmontero/opencode-skills --skill reviewing-security in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/reviewing-security/ (personal) or .claude/skills/reviewing-security/ (project).

Which AI agents can use reviewing-security?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is reviewing-security safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains reviewing-security?

It is published by osmontero in osmontero/opencode-skills. It has 146 recorded installs.

More from osmontero/opencode-skills

View all →

designing-frontend-interfaces

osmontero/opencode-skills

Use when building or restyling any web interface — landing pages, dashboards, marketing sites, web apps, React/Vue components, HTML/CSS layouts, artifacts, posters — or when asked to make a UI look better, more polished, more distinctive, less generic, or less "AI-generated". Also use when a design brief, art direction, visual identity, type scale, or color system is needed before implementation.

Frontend & Design650 installs

designing-user-experience

osmontero/opencode-skills

Open the skill to read its SKILL.md instructions.

460 installs

reviewing-interface-quality

osmontero/opencode-skills

Open the skill to read its SKILL.md instructions.

363 installs

building-accessible-interfaces

osmontero/opencode-skills

Use when building or auditing any web UI for accessibility — keyboard navigation, screen readers, focus management, ARIA, color contrast, form labels and error announcements, reduced motion, or touch target size. Triggers include "is this accessible", "WCAG", "a11y", "screen reader", "keyboard navigation", "focus trap", "contrast ratio", "aria-label", or building modals, menus, tabs, comboboxes, toasts, and custom controls that must work without a mouse.

Frontend & Design350 installs

systematic-debugging

osmontero/opencode-skills

Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes

verifying-before-completion

osmontero/opencode-skills

Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always

157 installs

Popular security skills

View category →

azure-compliance

microsoft/azure-skills

Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.

OfficialSecurity567K installs

minimal-run-and-audit

lllllllama/rigorpilot-skills

Rigor Run skill for README-first deep learning repo reproduction. Use when the task is specifically to capture or normalize evidence from the selected smoke test or documented inference or evaluation command and write standardized reprooutputs/ files, including patch notes when repository files changed. Do not use for training execution, initial repo intake, generic environment setup, paper lookup, target selection, hidden scientific-meaning changes, or end-to-end orchestration by itself.

Security477.4K installs

seo-audit

coreyhaines31/marketingskills

When the user wants to audit, review, or diagnose SEO issues on their site. Also use when the user mentions "SEO audit," "technical SEO," "why am I not ranking," "SEO issues," "on-page SEO," "meta tags review," "SEO health check," "my traffic dropped," "lost rankings," "not showing up in Google," "site isn't ranking," "Google update hit me," "page speed," "core web vitals," "crawl errors," "indexing issues," "stuck on page 2," "striking distance keywords," "title tag rewrite," "low CTR," "local SEO," "Google Business Profile," or "map pack." Use this even if the user just says something vague like "my SEO is bad" or "help with SEO" — start with an audit. For building pages at scale to target keywords, see programmatic-seo. For adding structured data, see schema. For AI search optimization, see ai-seo.

Security238.7K installs

firebase-security-rules-auditor

firebase/agent-skills

Audits Firebase (Firestore, Cloud Storage) security rules for vulnerabilities, privilege escalation, role bypasses, create vs update inconsistencies, resource exhaustion, type safety, size limits, and hasOnly ownership checks. Use when auditing/reviewing rules, running red-team rule assessments, or scoring against auditor checklists. Don't use for Firebase CLI (login, deploy), Auth, Crashlytics, Remote Config, or database queries.

OfficialSecurity139.1K installs

audit

pbakaus/impeccable

Run technical quality checks across accessibility, performance, theming, responsive design, and anti-patterns. Generates a scored report with P0-P3 severity ratings and actionable plan. Use when the user wants an accessibility check, performance audit, or technical quality review.

Security81.9K installs

competitors

coreyhaines31/marketingskills

When the user wants to create competitor comparison or alternative pages for SEO and buyer-facing use. Also use when the user mentions 'alternative page,' 'vs page,' 'competitor comparison,' 'comparison page,' '[Product] vs [Product],' '[Product] alternative,' 'competitive landing pages,' 'how do we compare to X,' 'competitor teardown,' 'audit our competitor pages,' 'are our comparison pages out of date,' or 'competitive asset audit.' Use this for any content that positions your product against competitors. Covers four formats: singular alternative, plural alternatives, you vs competitor, and competitor vs competitor. For auditing existing claims (not researching competitors from scratch, which is competitor-profiling; not technical SEO on these pages, which is seo-audit), use the asset audit here. For internal battle cards and sales-specific competitor docs, see sales-enablement.

Security79.3K installs