Web application pentesting
API Pentesting --- REST, GraphQL, OpenAPI and Cloud Web
Why APIs deserve a dedicated chapter
Modern applications expose business logic via JSON, GraphQL and microservices. The OWASP API Security Top 10 (2023) lists specific risks: broken object-level access control (BOLA), broken authentication, excessive resource consumption, injection at the business logic layer. Classic web scanners (HTML crawling) often miss these surfaces.
KittySploit addresses this gap through:
- dedicated
scanner/http/modules (graphql_detect,swagger_detect); - a generic API fuzzer (
auxiliary/scanner/http/api_fuzzer); - the
api_importcommand to transform schemas or traffic into modules; - the agent with the
api-reviewprofile and HTTP intelligence (api_surface_detected).
Preparing the API workspace
workspace create api-review
workspace use api-review
scope add api.target.local
host add api.target.local
If the target is local with a self-signed certificate:
http https://api.target.local/health -k -I
The -k (--insecure) option disables TLS verification --- reserved for isolated test environment use.
Swagger and OpenAPI detection
Module scanner/http/swagger_detect
The module probes a list of common paths:
use scanner/http/swagger_detect
set rhost api.target.local
set rport 443
set ssl true
run
Paths tested (excerpt from source code modules/scanner/http/swagger_detect.py):
/swagger, /swagger.json, /swagger-ui.html, /api-docs,
/v2/api-docs, /v3/api-docs, /openapi.json, /openapi.yaml.
A low finding signals documentation disclosure: often critical in
production (complete enumeration of operations) but expected in isolated test environment to accelerate testing.
Targeted mass scan for the API
scanner -u https://api.target.local --module swagger_detect -k
scanner -u https://api.target.local --tags api,swagger --threads 3
search swagger --type scanner --protocol http
Retrieving the schema
Once the path is found (e.g.\ /v3/api-docs):
http https://api.target.local/v3/api-docs -k -o /tmp/openapi.json
http https://api.target.local/swagger.json -k
Verify the JSON/YAML format before import.
GraphQL detection
Module scanner/http/graphql_detect
use scanner/http/graphql_detect
set rhost api.target.local
set rport 443
set ssl true
run
Probed paths: /graphql, /graphiql, /api/graphql, /query,
/v1/graphql, /altair. The module attempts introspection:
POST {"query": "{ __schema { types { name } } }"}
Response 200 with data or __schema indicates active introspection.
Typical GraphQL risks
- Open introspection --- complete map of the schema;
- Depth / complexity --- DoS via nested queries;
- BOLA --- access to another user's
user(id:)via mutations; - Injection --- arguments passed to SQL or OS without sanitization.
Manual testing with http
http https://api.target.local/graphql -k -X POST \
-H "Content-Type: application/json" \
-j '{"query":"{ __typename }"}'
http https://api.target.local/graphql -k -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TOKEN_LAB" \
-j '{"query":"{ users { id email } }"}'
API fuzzing with api_fuzzer
Loading the module
use auxiliary/scanner/http/api_fuzzer
set rhost api.target.local
set rport 443
set ssl true
show options
run
The module tests dozens of API paths (/api/v1, /rest, /oauth,
/health…) and multiple HTTP methods (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD,
TRACE). It applies fuzzing payloads to parameters and JSON bodies.
Prudent configuration
set threads 5
set timeout 10
run
Reduce threads on a fragile backend. Watch for 429 (rate limit) and 503 codes.
Interpreting results
- 200/201 on
/adminwithout auth indicates access control failure (OWASP API1). - 500 with stack trace indicates misconfiguration or information leakage.
- 405 vs 401 --- distinguish forbidden method from protected resource.
- Discovered endpoints --- feed
api_importor manual tests.
The api_import command
Role and inputs
api_import generates KittySploit modules (scanner, fuzzer) from:
- OpenAPI/Swagger specifications (JSON or YAML);
- GraphQL introspection responses (JSON);
- captured traffic: HAR, KittyProxy JSON, HTTP request list.
Implementation: interfaces/command_system/builtin/api_import_command.py, engine
core/api_module_generator/generator.py.
Syntax
api_import <schema_or_traffic_file> [--type auto|openapi|graphql|traffic]
api_import openapi.json
api_import graphql-introspection.json --type graphql --name internal_graphql
api_import kittyproxy_traffic.har --type traffic --kind scanner --force
Important options:
--type auto--- automatic format detection;--name--- pack name (e.g.\internal_graphql);--kind scanner,fuzzer--- generated module types;--module-dir--- defaultmodules/generated/api;--artifact-dir--- defaultartifacts/api_module_packs;--preview--- normalized inventory without writing files;--force--- overwrite existing modules.
Preview then generation workflow
api_import /tmp/openapi.json --preview
api_import /tmp/openapi.json --name lab_rest_api --kind scanner,fuzzer
Expected output: files in modules/generated/api/, manifest in
artifacts/api_module_packs/, unit tests under .../tests.
python -m unittest discover -s artifacts/api_module_packs/<pack>/tests
Import from KittyProxy traffic
proxy start; browse the SPA application that consumes the API.- Export the HAR or flow JSON.
api_import capture.har --type traffic --name spa_traffic.- Run the generated scanner against the isolated test target.
This workflow reconstructs an API surface that Swagger does not document (internal endpoints, deprecated versions).
REST testing with the http command
Overview
http (interfaces/command_system/builtin/http_command.py) sends HTTP
requests from the CLI, curl-style. It respects the framework proxy (KittyProxy, Tor) if configured.
Essential options
-H / --header | Header Key: Value (repeatable) |
-d / --data | Raw body |
-j / --json | JSON body (automatic Content-Type) |
-k / --insecure | Ignore TLS certificate errors |
-L / --location | Follow redirects |
-I / --head | HEAD request |
-i / --include | Display response headers |
-o / --output | Write body to a file |
--proxy | One-off proxy for this request |
-A / --user-agent | Custom User-Agent |
Common REST cases
Bearer authentication:http https://api.target.local/v1/users -k \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Resource creation:
http https://api.target.local/v1/items -k -X POST \
-H "Authorization: Bearer TOKEN" \
-j '{"name":"test-isolated test environment","qty":1}'
BOLA test (IDOR):
http https://api.target.local/v1/orders/1001 -k \
-H "Authorization: Bearer TOKEN_USER_A"
http https://api.target.local/v1/orders/1002 -k \
-H "Authorization: Bearer TOKEN_USER_A"
If a 200 response on 1002 reveals another user's data, document API1
(BOLA) with both requests as evidence.
http https://api.target.local/v1/items/999 -k -X DELETE \
-H "Authorization: Bearer TOKEN_LAB"
Chain with scanners
scanner -u https://api.target.local --module swagger_detect -k
http https://api.target.local/v3/api-docs -k -o /tmp/spec.json
api_import /tmp/spec.json --name lab_api
search lab_api
set rhost api.target.local
set ssl true
run
The generated module path is created under modules/generated/api/ and depends on the import name.
OWASP API Security and KittySploit modules
| API# | OWASP API risk | KittySploit approach |
|---|---|---|
| API2 | Broken auth | http without token; invalid JWTs; api_fuzzer on /auth |
| API3 | Excessive data exposure | GraphQL introspection; verbose JSON responses |
| API4 | Resource consumption | limit threads; manual pagination tests |
| API5 | BFLA | http -X POST on admin routes with standard user token |
| API6 | Business flow | agent + manual review (beyond generic scan) |
| API7 | SSRF | HTTP SSRF modules if API triggers URL fetch |
| API8 | Misconfiguration | swagger_detect, exposed_env_detect |
| API9 | Inventory | api_import + client documentation |
| API10 | Unsafe APIs | input validation via fuzzer and manual tests |
Browser server and client-side API surfaces
browser_server command
The browser exploitation server (core/browser_server.py,
browser_server start) records browser sessions and injects a
control script (BeEF-like mode). For API pentesting, the main interest is capture
of application traffic: an SPA loaded in the instrumented browser generates
/api/... calls visible via browser_server sessions and exportable to
api_import --type traffic.
browser_server start --host 127.0.0.1 --port 3000
browser_server status
browser_server inject
browser_server sessions
Hybrid web + API workflow
- Start
browser_serverand/or KittyProxy. - Load the web application that consumes the API.
- Collect XHR/fetch requests.
api_importon the traffic; complement with OpenAPI if available.- Targeted
httptests on undocumented endpoints.
KittySploit agent --- api-review profile
Profile definition
The api-review profile (interfaces/command_system/builtin/agent/mission_profiles.py) configures:
safety_profile: discreet;approved_risks: [read, active];request_budget: 30;http_replay: safe;- description: ``API surface validation without destructive actions''.
Typical launch
agent https://api.target.local --profile api-review
agent https://api.target.local --profile api-review --goal "review REST and GraphQL"
agent https://api.target.local --profile api-review --plan-only
agent https://api.target.local --profile api-review --no-exploit
Combined with prior discovery:
scanner -u https://api.target.local --tags api --threads 3 -k
agent https://api.target.local --profile api-review --reuse-proxy-auth
Internal HTTP intelligence
The agent classifies requests with signals such as api_surface_detected,
graphql_surface_detected or swagger_surface_detected. These signals,
produced by http_intelligence.py, steer the plan toward graphql_detect,
swagger_detect or generated modules.
Safeguards
--plan-only--- plan without execution;--no-exploit--- no exploitation modules;--request-budget N--- request ceiling;- custom TOML policy to forbid DELETE.
Cloud web integration (Firebase, actuators)
APIs are not always at /api/v1. KittySploit includes ``cloud web'' scanners:
use scanner/http/firebase_fingerprint_detect
set rhost api.target.local
set ssl true
run
use scanner/http/firebase_rtdb_public_access_detect
set rhost api.target.local
run
use scanner/http/spring_actuator_detect
set rhost api.target.local
set rport 443
set ssl true
run
An exposed Spring actuator (/actuator/env) equals an API configuration leak
(secrets, internal URLs). Document as API8 (misconfiguration).
Complete methodology --- checklist
- Scope ---
scope add, engagement letter, test accounts. - Passive detection ---
swagger_detect,graphql_detect. - Schema collection ---
http -o, client documentation. - Import ---
api_import --preview, then generation. - Light fuzzing ---
api_fuzzerwith lowthreads. - Manual tests --- BOLA, auth, validation with
http. - Agent ---
--profile api-review --plan-only, human validation. - Reporting ---
vuln add,campaign --formats report.
Writing API findings
Each finding should contain:
- endpoint and method (e.g.\
GET /v1/users/\{id\}); - account used and proof of unauthorized access;
- truncated JSON excerpt (no full dump);
- OWASP API Top 10 reference;
- remediation (object-level control, OAuth scopes, introspection disable).
Troubleshooting
- api_import fails --- verify valid JSON; specify
--type. - Generated modules not found ---
sync now; pathmodules/generated/api. - 401 everywhere --- expired token; replay login via
http. - GraphQL 400 --- Content-Type
application/json; escape quotes in-j. - Agent exceeds budget --- increase
--request-budgetor split by subdomain.