agentsclimarketplace

Openapi spec security scan

Skill Dolphinllc/claude-security-skills/skills/defensive/web/openapi-spec-security-scan

Defensive security skills for Claude Code and the Claude Agent SDK — web applications and generative AI systems.

Install
npx -y skills add Dolphinllc/claude-security-skills --skill openapi-spec-security-scan

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Defensive security scan for OpenAPI 3.x specifications (openapi.yaml / openapi.json). Detects missing global security, unprotected mutating operations, HTTP-only servers, loose schemas (additionalProperties true, missing required), wildcard CORS, missing 401/403 responses, PII in examples, and weakly-typed parameters. Invoke when the user asks to "review", "audit", or "scan" an OpenAPI / Swagger spec, or when editing files named openapi.{yaml,json}, swagger.{yaml,json}, or under api/ directories.

SKILL.md

6.8 KB, as published. Nobody here has run it

OpenAPI Spec Security Scan

Defensive scan for OpenAPI 3.0 / 3.1 specifications. The spec is the contract — gaps here become real vulnerabilities downstream in generated servers and clients. Reports findings using the shared scoring schema.

Scope

  • openapi.{yaml,yml,json}, swagger.{yaml,yml,json} (any Swagger 2.0 → upgrade)
  • Files referenced via $ref (components/**, paths/**)
  • Generated server stubs only as cross-reference; rules apply to the spec itself

Procedure

  1. Parse the document (use yaml/json tooling; do not regex).
  2. Resolve $refs to evaluate effective schemas.
  3. Walk paths × methods and apply rules below.
  4. Walk components.schemas for type tightness.

Rules

IDSeverityDetectionFix
OAS-VER-001mediumDocument is Swagger 2.0 (swagger: "2.0")Upgrade to OpenAPI 3.1
OAS-SEC-001criticalNo top-level security: and at least one mutating operation has no security overrideDefine global security: and override per public operation
OAS-SEC-002highOperation POST/PUT/PATCH/DELETE has security: [] (explicitly anonymous)Remove or gate behind explicit auth
OAS-SEC-003highsecuritySchemes declares type: http, scheme: basic and is referenced from operations served over HTTP (not HTTPS)Require HTTPS-only (see OAS-SRV-001); prefer bearer/oauth2
OAS-SEC-004mediumAPI-key scheme using in: queryMove to in: header; query strings leak via referrer/log
OAS-SEC-005mediumOAuth2 flow declares scopes that are never required by any operation (or vice-versa)Reconcile scopes ↔ operations
OAS-SRV-001highservers: contains an http:// URL (not https://) for a non-localhost hostUse https://
OAS-CORS-001highSpec advertises Access-Control-Allow-Origin: * (in response headers) on operations requiring authRemove wildcard; document origin allowlist
OAS-RESP-001highMutating operation declares 200/201 but no 401 and no 403Add 401 and 403 response refs
OAS-RESP-002mediumOperation declares default response only (no specific codes)Enumerate 200/400/401/403/404/5xx
OAS-RESP-003low5xx response includes detailed schema (stack trace fields, internal ids)Use generic error envelope
OAS-PARAM-001highPath/query parameter has type: string without pattern, enum, format, or maxLengthConstrain — every untyped string is an injection seam
OAS-PARAM-002mediumInteger parameter without minimum/maximum (allows pagination DoS / overflow)Set bounds
OAS-SCHEMA-001highObject schema has additionalProperties: true (or default) on request bodySet additionalProperties: false; clients should not send unknown fields
OAS-SCHEMA-002mediumObject schema missing required: for fields that are not nullable in the implementationDeclare required:
OAS-SCHEMA-003mediumString field missing maxLength on user-supplied bodiesAdd maxLength to bound payloads
OAS-SCHEMA-004highResponse schema for User/Account/auth model includes fields like password, password_hash, totp_secret, api_keyRemove from response schema
OAS-EX-001highexample / examples contain real-looking PII, JWTs, or API keys (entropy heuristic + key-shaped names)Replace with synthetic placeholders
OAS-FILE-001mediumMultipart upload operation does not constrain format: binary size (no maxLength on encoding, no documented limit)Document limits; enforce server-side
OAS-DEP-001lowOperation marked deprecated: true still listed without sunset date in descriptionAdd removal timeline
OAS-WEBHOOK-001highOpenAPI 3.1 webhooks: defined without a signature scheme (HMAC, JWS) documentedDocument signing scheme; require it on receiver

Wrong vs. right

OAS-SEC-001 (no global security)

# ❌ paths declare no security; global is empty → all anonymous
openapi: 3.1.0
paths:
  /users:
    post:
      summary: Create user
      responses:
        "201": { $ref: "#/components/responses/User" }
# ✅ Global default + explicit overrides
openapi: 3.1.0
security:
  - bearerAuth: []
paths:
  /users:
    post:
      summary: Create user
      security:
        - bearerAuth: [users.write]
      responses:
        "201": { $ref: "#/components/responses/User" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "403": { $ref: "#/components/responses/Forbidden" }
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

OAS-SCHEMA-001 + OAS-PARAM-001 (loose types)

# ❌
components:
  schemas:
    CreateUser:
      type: object
      properties:
        email: { type: string }
        role:  { type: string }
      # additionalProperties default = true
# ✅
components:
  schemas:
    CreateUser:
      type: object
      additionalProperties: false
      required: [email, role]
      properties:
        email:
          type: string
          format: email
          maxLength: 254
        role:
          type: string
          enum: [member, admin]

OAS-SCHEMA-004 (response leaks)

# ❌ Returning the password hash to clients
User:
  type: object
  properties:
    id: { type: string, format: uuid }
    email: { type: string }
    password_hash: { type: string }   # ← never expose
# ✅ Define a separate response model
UserPublic:
  type: object
  required: [id, email]
  additionalProperties: false
  properties:
    id: { type: string, format: uuid }
    email: { type: string, format: email }

OAS-EX-001 (PII in examples)

# ❌ Real-looking PII shipped in the spec → leaked via SDK docs / API portals
example:
  email: [email protected]
  phone: "+81-90-1234-5678"
  api_key: sk-live-7c8a9d1e2f3b...
# ✅ Obviously synthetic
example:
  email: [email protected]
  phone: "+81-90-0000-0000"
  api_key: REPLACE_ME

References

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.