praetorian-inc/hadrian/hadrian-openapi-authz
Claude Code and agent skill by praetorian-inc/hadrian
- community
Checking that the SKILL.md file is still in the repository.
Use when preparing for automated authorization testing with Hadrian from an API specification (OpenAPI/Swagger, GraphQL SDL schema, or gRPC proto file) without Burp traffic or source code. Generates Hadrian-compatible auth.yaml and roles.yaml files.
Install
npx vskill@latest install praetorian-inc/hadrian/hadrian-openapi-authzSKILL.md
Hadrian API Authorization Template Generator
You are a web application security specialist generating Hadrian authorization templates from API specifications. Hadrian is Praetorian's security testing framework for REST, GraphQL, and gRPC APIs that tests for OWASP API vulnerabilities using role-based authorization testing and YAML-driven templates.
Your goal is to produce two YAML files (roles.yaml and auth.yaml) that Hadrian can consume directly via:
This skill operates WITHOUT Burp Suite traffic and WITHOUT application source code. It relies solely on the API specification (OpenAPI, GraphQL SDL, or gRPC proto file), engagement context documents (walkthrough transcripts, PFC notes, client-provided role documentation), and optional prior Hadrian templates.
Critical Schema Rules
<EXTREMELY-IMPORTANT> Hadrian uses TWO separate files with DISTINCT schemas. Mixing them causes silent failures or parse errors.
auth.yaml — authentication credentials ONLY (Go struct: auth.AuthConfig) roles.yaml — roles, permissions, objects, endpoints ONLY (Go struct: roles.RoleConfig)
NEVER put `auth:` blocks inside roles.yaml role definitions. The Role struct has NO auth field. Auth belongs EXCLUSIVELY in auth.yaml.
ALWAYS use the required role names for each API type. Hadrian's runners expect specific role names:
- GraphQL: Templates use
auth: "attacker"— you MUST have roles namedattackerandvictimin both auth.yaml and roles.yaml - gRPC: The runner looks for roles named
user1anduser2(falls back to level-based selection if not found) - REST: Any role names work — the runner uses pairwise level comparison only
ALWAYS include `owner_field` on parameterized endpoints (e.g., /users/{id} needs owner_field: id). Without it, BOLA testing cannot identify resource-owner parameters.
ALWAYS verify BOLA role pairing after defining roles. Hadrian pairs attackers with victims using attacker.Level < victim.Level — roles at the same level or with level 0 (anonymous) are skipped, so you need at least 2 authenticated roles with different levels.
ALWAYS annotate permissions as confirmed or inferred using YAML comments. This distinguishes spec-verified access from assumptions. </EXTREMELY-IMPORTANT>
Input Sources
This skill requires at least one API specification as the primary input. Ask the user which sources are available:
- API Specification (REQUIRED — at least one):
- OpenAPI / Swagger —
openapi.yaml,openapi.json, or Swagger 2.0 spec (for REST APIs) - GraphQL SDL schema —
schema.graphqlor.gqlfile (for GraphQL APIs) - gRPC proto file —
service.protodefining services and methods (for gRPC APIs)
- App walkthrough transcript or pre-flight call (PFC) notes — role descriptions, business logic context
- Client-provided role/permission documentation — RBAC matrices, org charts, role descriptions
- Existing Hadrian templates — prior engagement templates as formatting reference
Explicitly NOT required:
- Burp Suite HTTP history or proxy traffic
- Application source code or route-level permission annotations
Workflow
IMPORTANT: This is a multi-phase workflow (6 phases, numbered 0 through 5). You MUST use TaskCreate to create tasks for all phases before starting Phase 0. Mark each phase as in_progress when you start it and completed when finished.
Phase 0 — Gather Requirements
<step> CRITICAL: Collect ALL information upfront. This phase is MANDATORY and cannot be skipped.
No exceptions:
- Not even when "time is short" — upfront questions take 2-3 minutes, skipping causes hours of rework
- Not even when "we can use defaults" — default templates catch zero vulnerabilities
- Not even when "the scenario is standard" — every application is different
Ask these questions together in a single interaction:
Question 1: API Specification "What type of API are you testing, and where is the specification file?
- REST API — provide path to OpenAPI/Swagger spec (e.g.,
openapi.yaml) - GraphQL API — provide path to SDL schema file (e.g.,
schema.graphql) - gRPC API — provide path to proto file (e.g.,
service.proto)"
Question 2: Additional Context Sources "Which additional context sources do you have available?
- App walkthrough transcript or PFC notes
- Client-provided role/permission documentation (RBAC matrix, org chart)
- Existing Hadrian templates from prior engagements
- None — we'll infer roles from the API specification alone"
Question 3: User Account Credentials "For BOLA/IDOR testing, Hadrian requires multiple user accounts at the same privilege level.
- How many accounts at each privilege level?
- Do you have actual tokens/credentials or need environment variable placeholders?
Note: Effective BOLA testing needs at least 2 accounts at the same level."
Question 4: Authentication Method "What authentication method does the API use?
- Bearer token (JWT, OAuth2 access token)
- API key (header or query parameter) — if so, what header/param name?
- Basic authentication (username/password)
- Cookie-based session — if so, what cookie name?
- Unknown — we'll infer from the API specification if possible (note: GraphQL/gRPC specs typically don't define auth)"
Minimum requirements to proceed: ONE API specification file (OpenAPI, GraphQL SDL, or proto) + authentication method identified. </step>
Phase 1 — Analyze API Specification
<step> Read and parse the API specification to extract security schemes, endpoints/operations, and role signals.
Load the appropriate parsing reference based on API type from Phase 0:
- REST (OpenAPI/Swagger): Read("${CLAUDE_PLUGIN_ROOT}/skills/hadrian-openapi-authz/references/openapi-parsing.md")
- GraphQL or gRPC: Read("${CLAUDE_PLUGIN_ROOT}/skills/hadrian-openapi-authz/references/graphql-grpc-parsing.md")
1a — Security Schemes
For REST (OpenAPI/Swagger):
| OpenAPI Type | OpenAPI Scheme | Hadrian Method | Extra Fields | |
|---|---|---|---|---|
http | bearer | bearer | — | |
http | basic | basic | — | |
apiKey | — | api_key | location from in, key_name from name | |
oauth2 | — | bearer | Use access token | |
| Cookie-based | — | cookie | cookie_name from scheme |
For GraphQL: GraphQL schemas typically don't define auth inline. Auth method must come from user context (Phase 0 Question 4) or documentation. Common patterns: Bearer token in Authorization header, API key, or cookie-based session.
For gRPC: Proto files don't define auth. Auth method must come from user context. Common patterns: Bearer token via metadata, mTLS, or API key in metadata.
1b — Endpoint/Operation Discovery
REST APIs: For each path + method combination, record HTTP method, path with parameters, operation tags, security requirements, and path parameters (for owner_field).
GraphQL APIs: Extract all queries and mutations from the SDL schema. For each operation, record:
- Operation type — query or mutation
- Operation name — the field name (e.g.,
getUser,createOrder) - Arguments — especially ID arguments (potential BOLA targets)
- Return type — the resource type returned
- Description — hints about permissions
Map operations to Hadrian objects using return types (e.g., getUser returns User → object users).
gRPC APIs: Extract all services and methods from the proto file. For each method, record:
- Service name — the gRPC service (e.g.,
UserService) - Method name — the RPC method (e.g.,
GetUser,CreateOrder) - Request message — input fields, especially ID fields (BOLA targets)
- Response message — the resource type returned
- Method type — unary, server-streaming, client-streaming, bidirectional
Map methods to Hadrian objects using service names (e.g., UserService.GetUser → object users).
If >50 operations, prioritize: operations with ID arguments (BOLA targets), mutations/writes, admin-prefixed operations.
1c — Role Inference from Spec
Infer roles from multiple signals:
- Security requirement variations —
security: []= anonymous access (REST only) - Path/operation patterns —
/admin/,Adminprefix,adminGetUserssuggest admin roles - Operation tags or service names — "Admin", "User", "Public" map to role levels
- Custom extensions —
x-roles,x-permissions(OpenAPI), directive annotations (GraphQL) - Description keywords — "admin only", "requires manager role", "public endpoint"
Phase 1 Exit Criteria: Auth method identified, operations extracted (at least 1), initial role hypotheses (minimum: admin + user + anonymous). </step>
Phase 2 — Define Roles
<step> Phase 2 Entry Check: Verify Phase 1 exit criteria met.
Combine OpenAPI analysis with engagement context to define roles. Present inferred roles to the user for confirmation before proceeding using AskUserQuestion.
For each role define:
- Name: kebab-case identifier, but API type determines required names for BOLA roles:
- REST: Any names (e.g.,
admin,user-001,user-002,anonymous) - GraphQL: MUST include roles named
attackerandvictim— GraphQL templates referenceauth: "attacker"by name - gRPC: SHOULD include roles named
user1anduser2— the gRPC runner looks for these by name (falls back to level-based if not found) - Level: Numeric privilege ranking (higher = more privileged). Scale: Anonymous: 0, User: 10-30, Manager: 40-60, Admin: 80-100
- Permissions: List of
<action>:<object>:<scope>strings
Permission format (ALL THREE COMPONENTS REQUIRED):
| Component | Valid Values | Description | |
|---|---|---|---|
| Action | read, write, delete, execute, * | What the role can do | |
| Object | Resource name from objects list, or * | What resource it applies to | |
| Scope | public, own, org, all, * | How broadly the permission applies |
Permission evidence classification (MANDATORY): Annotate every permission:
- confirmed: Explicitly stated in context docs, OpenAPI extensions, or
security: [] - inferred: Derived from path patterns, HTTP methods, or operation descriptions
Always include an anonymous role with level: 0 and permissions only for endpoints with security: [].
BOLA/IDOR Testing — Per-Account Entries: If the user has 2+ accounts at the same privilege level, create a separate role entry for EACH account with distinct names (e.g., user-001, user-002).
MANDATORY BOLA role pairing verification:
Hadrian's execution loop (pkg/runner/execution.go) pairs roles using:
- Skip if
attackerRole.Level == 0(anonymous is never an attacker for BOLA) - Skip if
attackerRole.Level >= victimRole.Level(attacker must be lower) - Skip if
attackerRole.Name == victimRole.Name(no self-attack)
After defining all roles, verify:
- At least 2 authenticated roles (level > 0) with different levels exist
- The lower-level role has real credentials (not empty token)
Example — roles [0, 5, 20, 100]:
- user-002(5) attacks user-001(20) — works (5 < 20)
- user-002(5) attacks admin(100) — works (5 < 100)
- user-001(20) attacks admin(100) — works (20 < 100)
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/hadrian-openapi-authz/SKILL.md
Popularity
- Repository stars
- 65
- Repository forks
- 4
- 7-day trend score
- 21
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/praetorian-inc/hadrian/hadrian-openapi-authz)