apifuzz 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,350 @@
1
+ Metadata-Version: 2.5
2
+ Name: apifuzz
3
+ Version: 0.2.0
4
+ Summary: OpenAPI-driven security scanner for authorized staging APIs (OWASP API Top 10).
5
+ Project-URL: Homepage, https://github.com/mateivarvara100-cloud/apisecurityfuzzer
6
+ Project-URL: Issues, https://github.com/mateivarvara100-cloud/apisecurityfuzzer/issues
7
+ Author: mateivarvara100-cloud
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: api,bola,idor,openapi,owasp,scanner,security,swagger
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Security
19
+ Classifier: Topic :: Software Development :: Testing
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: httpx>=0.27
22
+ Requires-Dist: openapi-spec-validator>=0.7
23
+ Requires-Dist: prance>=23.6
24
+ Requires-Dist: pydantic>=2.6
25
+ Requires-Dist: rich>=13.7
26
+ Requires-Dist: typer>=0.12
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=8; extra == 'dev'
29
+ Requires-Dist: ruff>=0.6; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # apifuzz
33
+
34
+ A command-line security scanner that reads an OpenAPI/Swagger spec and tests the API it
35
+ describes for common OWASP API Top 10 flaws. You point it at an API you are authorized to test,
36
+ give it two test accounts, and get a report a developer can act on: the endpoint, the evidence,
37
+ the severity, and the fix.
38
+
39
+ > **Status.** Five checks work today: `bola` (BOLA/IDOR by token swapping), `auth-required`,
40
+ > `mass-assignment`, `rate-limit` and `injection` (SQL/NoSQL, detection only). SARIF output is
41
+ > planned, not built. Every check is verified against the bundled VulnShop lab on each test run.
42
+
43
+ ```text
44
+ $ make demo
45
+ ...
46
+ 12 endpoints scanned · 7 findings (2 critical, 4 high, 1 medium) · 5 checks run
47
+ What was tested
48
+ +--------------------------------------------------------+
49
+ | Check | Tested | Not tested | Not applicable |
50
+ |-----------------+--------+------------+----------------|
51
+ | auth-required | 7 | 0 | 5 |
52
+ | bola | 4 | 0 | 8 |
53
+ | injection | 2 | 0 | 10 |
54
+ | mass-assignment | 2 | 0 | 10 |
55
+ | rate-limit | 2 | 0 | 10 |
56
+ +--------------------------------------------------------+
57
+ 111 requests sent to http://localhost:8000
58
+ ```
59
+
60
+ ## What it checks
61
+
62
+ | Check | OWASP | How it works, in one line |
63
+ | --- | --- | --- |
64
+ | `bola` | API1:2023 | Logs in as two users and checks whether one can read the other's objects (`GET /orders/{id}`). |
65
+ | `auth-required` | API2:2023 | Calls endpoints the spec says need a login with no credentials, and reports the ones that answer. |
66
+ | `mass-assignment` | API3:2023 | Sends an update or create with one extra field the spec doesn't list (such as `role`) and reads the object back to see if it was saved. |
67
+ | `rate-limit` | API4:2023 | Sends a small burst of identical requests to login and search endpoints and looks for a `429` or rate-limit headers. |
68
+ | `injection` | API8:2019 | Sends inert marker values to query-string parameters and to JSON body fields of login/search endpoints, and watches the response *shape* for a database error, an always-true/always-false differential, or an accepted NoSQL operator object. Detection only. |
69
+
70
+ All probes are meant to detect a flaw, not to use it. Details for each check are under
71
+ [How each check works](#how-each-check-works).
72
+
73
+ ## Quickstart
74
+
75
+ Needs Python 3.11 or newer, and Docker for the demo.
76
+
77
+ ```bash
78
+ python -m venv .venv
79
+ # Windows: .venv\Scripts\activate macOS/Linux: source .venv/bin/activate
80
+ pip install -e ".[dev]"
81
+
82
+ make demo # macOS/Linux, or Windows with make
83
+ powershell -File lab/demo.ps1 # Windows without make
84
+ ```
85
+
86
+ The demo boots VulnShop (a deliberately vulnerable API, see [Lab target](#lab-target-vulnshop))
87
+ in Docker, logs in both lab accounts, scans it, and writes `report.html` and `report.json`.
88
+
89
+ ## Scan your own API
90
+
91
+ ```bash
92
+ apifuzz checks # list the available checks
93
+ apifuzz endpoints openapi.json # see what the spec contains; sends nothing
94
+ apifuzz scan openapi.json --i-have-authorization --base-url https://staging.example.com
95
+ ```
96
+
97
+ `scan` refuses to run without `--i-have-authorization`. It contacts only the base URL's host,
98
+ plus any `--allow host[:port]` entries, and never follows redirects.
99
+
100
+ **The target.** Pass `--base-url` or set `APIFUZZ_BASE_URL`. Without either, the spec's `servers`
101
+ entry is used only if the spec was downloaded from that same host, or you listed the host with
102
+ `--allow`. A spec is a document: it may not choose the target (and receive your test tokens) on
103
+ its own.
104
+
105
+ **Test accounts.** `bola` needs two different accounts, A and B; `mass-assignment` needs A. Give
106
+ each one either a token (`APIFUZZ_TOKEN_A` / `_B`) or a username and password (`APIFUZZ_USER_A` /
107
+ `APIFUZZ_PASSWORD_A`, and the same for B). They are read only from the environment or `.env`
108
+ (see [.env.example](.env.example)), never from flags, so they stay out of shell history.
109
+
110
+ - With a username and password, apifuzz POSTs them to `APIFUZZ_LOGIN_PATH` (default `/login`) and
111
+ reads the token from the answer. `APIFUZZ_LOGIN_FORMAT=form` sends form fields instead of JSON;
112
+ `APIFUZZ_LOGIN_USER_FIELD` / `APIFUZZ_LOGIN_PASSWORD_FIELD` rename the fields.
113
+ - The token is sent the way the spec's security scheme says (a bearer token, an API-key header,
114
+ or a cookie). `APIFUZZ_AUTH_HEADER` / `APIFUZZ_AUTH_PREFIX` override that.
115
+ - Before scanning, each token is tried on a protected endpoint. The scan stops if a token is
116
+ refused, if A and B have the same token, or if both turn out to be the same user. Otherwise it
117
+ would test nothing and report a clean API, or "prove" two accounts can read each other's data.
118
+
119
+ | Option | What it does |
120
+ | --- | --- |
121
+ | `--base-url` | Root URL of the API |
122
+ | `--allow` | Extra host the scan may contact (repeatable) |
123
+ | `--only` / `--skip` | Run only, or leave out, a check id (repeatable) |
124
+ | `-m`, `-p`, `-t`, `--auth` | Scan only some endpoints: by method, path pattern, tag, or login needed (`login`/`none`) |
125
+ | `--shared` | Path pattern whose objects are shared between users on purpose, e.g. `'/posts/*'`; `bola` skips it (repeatable) |
126
+ | `--burst` | Requests the `rate-limit` check sends to one endpoint (default 15, at most 50) |
127
+ | `--max-requests` | Stop the scan after this many requests (default 1000) |
128
+ | `--delay` | Seconds to wait between requests |
129
+ | `--timeout` | Seconds to wait for each response (default 10) |
130
+ | `--require-docker` | Only scan if every target is a running local Docker container. See below. |
131
+ | `--fail-on` | Exit 1 if any finding is at least this severe: `info`…`critical`, or `never` (default `high`) |
132
+ | `--json` | Print the report as JSON instead of tables |
133
+ | `--json-out FILE` / `--html FILE` | Also write a JSON report, or a standalone HTML report (one file, no scripts) |
134
+ | `--redact` / `--no-redact` | Make reports safe to share (default: on). See [Reports](#reports). |
135
+
136
+ **Exit codes:** `0` no findings at or above `--fail-on`; `1` findings at or above it; `2` usage
137
+ or configuration error, a failed login or dead token, or a target where no request got an answer.
138
+ An unreachable API is an error, not a clean result, so it can't pass a CI job by being down.
139
+
140
+ Every request carries `User-Agent: apifuzz/<version>`, so the target's logs show where the
141
+ traffic came from.
142
+
143
+ ### Docker-only mode
144
+
145
+ With `--require-docker` (or `APIFUZZ_REQUIRE_DOCKER=1`), apifuzz asks Docker which containers are
146
+ running before it sends anything. It scans only if the base URL, every `--allow` entry, and the
147
+ spec URL (when the spec is downloaded) are ports that one of them publishes. The host must be
148
+ written as `localhost`, `127.0.0.1`, `::1`, or a container's own IP; other hostnames are refused
149
+ without a DNS lookup. The allowlist then holds only those exact `host:port` pairs. Check a target
150
+ on its own, without scanning, with:
151
+
152
+ ```bash
153
+ apifuzz verify-docker http://localhost:8000
154
+ ```
155
+
156
+ ## Reports
157
+
158
+ Every finding has a severity, its OWASP category, the evidence (the exact requests and
159
+ responses), a fix, and a `fingerprint` that stays the same between runs so two reports can be
160
+ compared. A finding is reported only after a repeated request confirms it.
161
+
162
+ Every report also says **what was tested**. For each check it counts the endpoints it tested,
163
+ the ones it could not judge (with the reason), and the ones it doesn't apply to. "No findings"
164
+ is only good news for endpoints that were tested.
165
+
166
+ With `--redact` (the default), JSON and HTML reports are safe to attach to a ticket:
167
+
168
+ - `Authorization`, cookie and API-key headers are hidden, and the test accounts' tokens are
169
+ replaced wherever else they appear (URLs, bodies, warnings).
170
+ - In bodies, values of fields such as `email`, `phone`, `password` and `token` are masked, and
171
+ e-mail addresses are masked in plain text. A BOLA finding's evidence is another user's data.
172
+ - Bodies are cut to a short excerpt.
173
+
174
+ The JSON report carries `schema_version`, `tool_version`, `target`, `started_at`, `duration_s`
175
+ and `requests_sent`.
176
+
177
+ ## How each check works
178
+
179
+ **`bola`.** First it does recon: it calls the protected GET endpoints that take no id (such as
180
+ `/me` or `/orders`) as account A and as account B, and notes which ids each account is shown,
181
+ and on which endpoint. Those real ids (numbers or strings such as UUIDs), plus 1–5 for numeric
182
+ ids, are requested on every `GET /thing/{id}` as A and as B. An object that both accounts receive
183
+ (the same object, not just the same status code), while a request with no token is refused, is
184
+ reported once a second request confirms it:
185
+
186
+ - **CRITICAL** when ownership is proven: `GET /orders` lists the id for one account only, yet
187
+ the other could read `GET /orders/{id}`.
188
+ - **HIGH** when it is likely: the object has an owner field (`owner`, `user_id`...). That is not
189
+ proof, because a public post names its author too.
190
+ - **LOW** when nothing shows whose object it is. It may be shared on purpose.
191
+ - Not reported: an object the API itself lists to both accounts, and paths marked `--shared`.
192
+
193
+ Ids are attributed per collection: an id seen in `/orders` says nothing about `/products/{id}`.
194
+ On a nested path such as `/users/{userId}/orders/{orderId}` the last id is probed and the ids
195
+ before it are filled with account A's own, so the question is whether B can read an object under
196
+ A's part of the tree. Only GET endpoints are probed, and recon sends only GETs.
197
+
198
+ **`auth-required`.** For GET/HEAD endpoints the spec marks as needing a login: one request with
199
+ no credentials. A 2xx answer, confirmed by a second request, is HIGH. A 401/403 is correct. Any
200
+ other answer (a 404 for the sample id, a 5xx) is counted as not tested.
201
+
202
+ **`mass-assignment`.** For PATCH/PUT endpoints, on one of account A's own objects: it reads the
203
+ object, then sends the update with one extra field the spec doesn't list as writable, and reads
204
+ the object back. A field that was saved is a finding: CRITICAL if it controls what the user may
205
+ do (`role`, `is_admin`, `verified`...), HIGH otherwise. The probe proves the flaw without using
206
+ it: a text field is set to the marker `apifuzz-probe`, never to `admin`, and the original value
207
+ is put back afterwards (the finding says whether that worked). Ids, owner fields, timestamps and
208
+ secrets are never written to. Create (POST) endpoints are probed the same way, but only when the
209
+ spec also has a DELETE and a GET for the created object: every object made for the test is
210
+ deleted straight after it is read, and the report names any that could not be. Without a DELETE
211
+ the endpoint is listed as not tested.
212
+
213
+ **`rate-limit`.** For login-like POST endpoints and search-like GET endpoints: a burst of
214
+ identical requests, one after another, stopping at the first `429` or `Retry-After` /
215
+ `RateLimit-*` header. Answers that get several times slower as the burst goes on also count as
216
+ throttling. If the whole burst is answered with no sign of throttling, a login endpoint
217
+ is HIGH and a search endpoint MEDIUM. Login attempts use made-up credentials for a user that
218
+ doesn't exist. Endpoints that create data or send messages (sign-up, password reset) are never
219
+ burst. This is detection, not a load test: the burst is capped at 50.
220
+
221
+ **`injection`.** On one input at a time it sends a benign baseline value, then a value with one
222
+ extra quote (`apifuzz'`), then an always-true and an always-false value (`apifuzz' OR '1'='1' -- `
223
+ / `apifuzz' AND '1'='2' -- `). A database error in the answer to the quote, or a result set that
224
+ differs between the always-true and always-false values, means the input is reaching a query
225
+ unescaped — HIGH, once the signal repeats on a second request. Two kinds of input are probed:
226
+ query-string parameters on GET/HEAD endpoints, and JSON body fields on endpoints that read or
227
+ authenticate (login / search / lookup / query shaped) — for body fields it also sends an operator
228
+ object (`{"$ne": …}`) where a scalar is expected, to catch NoSQL operator injection. Create and
229
+ update endpoints are never probed with a body, so the check can neither create nor change data;
230
+ the markers are inert, and it counts records, never reads their contents.
231
+
232
+ ## Lab target (VulnShop)
233
+
234
+ `lab/` contains VulnShop, a tiny deliberately vulnerable API (spec:
235
+ [lab/openapi.json](lab/openapi.json)). Each planted flaw is marked `PLANTED` in
236
+ [lab/app.py](lab/app.py); everything else behaves correctly, so a finding anywhere else is a
237
+ false positive.
238
+
239
+ | Route | Behaviour | Expected result |
240
+ | --- | --- | --- |
241
+ | `GET /orders/{id}` | Planted: checks the login but not the order's owner | `bola` (CRITICAL) |
242
+ | `GET /users/{id}` | Planted: doesn't check the login at all | `auth-required` (HIGH) |
243
+ | `PATCH /users/{id}` | Planted: saves every field in the body, including `role` | `mass-assignment` (CRITICAL) |
244
+ | `POST /login` | Planted: accepts any number of attempts, and pastes `username` into a SQL user lookup | `rate-limit` (HIGH), `injection` (HIGH) |
245
+ | `GET /search` | Planted: accepts any number of searches, and pastes `q` into a SQL query | `rate-limit` (MEDIUM), `injection` (HIGH) |
246
+ | `GET /me`, `GET /orders` | Correct: only the caller's own data | nothing |
247
+ | `POST /orders`, `DELETE /orders/{id}` | Correct: saves only the fields the spec allows; you can delete only your own orders | nothing |
248
+ | `GET /products/{id}` | Correct: shared on purpose with every logged-in user | nothing |
249
+ | `GET /invoices/{id}` | Correct: only the owner can read an invoice | nothing |
250
+
251
+ With `LAB_HARDENED=1` every planted flaw is fixed. This is the known-negative variant, and a scan
252
+ of it must report nothing:
253
+
254
+ ```bash
255
+ LAB_HARDENED=1 docker compose up -d --wait # PowerShell: $env:LAB_HARDENED="1"; docker compose up -d --wait
256
+ ```
257
+
258
+ The hardened lab limits logins to 5 per 30 seconds, so a second scan started right away is
259
+ refused at login with a clear message. Wait half a minute.
260
+
261
+ The container listens on `127.0.0.1:8000` only, runs as a non-root user with a read-only
262
+ filesystem and no capabilities, and keeps its data in memory (seeded the same way on every
263
+ start). The app refuses to start without `DEMO_MODE=1` and marks every response with an
264
+ `X-VulnShop-Lab` header, so it can't be mistaken for a real service.
265
+
266
+ Step by step instead of `make demo`:
267
+
268
+ ```bash
269
+ docker compose up -d --build --wait # start (first run builds the image)
270
+ apifuzz verify-docker http://localhost:8000 # confirm it's the lab container
271
+ apifuzz scan http://localhost:8000/openapi.json --i-have-authorization --require-docker --html report.html
272
+ docker compose down # stop
273
+ ```
274
+
275
+ Lab accounts: `alice`/`alice` (token `lab-token-alice`) and `bob`/`bob` (token `lab-token-bob`).
276
+ They exist only in the lab, so it's fine to put them in `.env`.
277
+
278
+ ## Architecture
279
+
280
+ ```mermaid
281
+ flowchart LR
282
+ spec[OpenAPI spec] --> loader[spec_loader] --> model[endpoint_model]
283
+ env[flags / .env] --> settings
284
+ settings --> session[session_manager]
285
+ model --> scanner
286
+ session --> scanner
287
+ scanner --> checks["checks: bola, auth-required,<br/>mass-assignment, rate-limit, injection"]
288
+ checks --> client[http_client<br/>allowlist, limits]
289
+ client --> target[(API under test)]
290
+ scanner --> report[report: table, JSON, HTML]
291
+ ```
292
+
293
+ The HTTP client is the only code that touches the target. Checks share one interface
294
+ (`Check.run(endpoint, context)`), so adding a check is one new module.
295
+
296
+ | File | What it does |
297
+ | --- | --- |
298
+ | `src/apifuzz/spec_loader.py` | Reads a spec from a file or URL, resolves its `$ref`s, validates it, and turns problems into clear errors. |
299
+ | `src/apifuzz/endpoint_model.py` | Turns the spec into a plain list of `Endpoint` objects. |
300
+ | `src/apifuzz/settings.py` | Combines flags, environment/`.env` and the spec into scan settings, including how tokens are sent and which target is confirmed. |
301
+ | `src/apifuzz/session_manager.py` | Logs the two test accounts in, and checks their tokens work and belong to two different users. |
302
+ | `src/apifuzz/http_client.py` | The only code that sends requests to a target. Enforces the allowlist and the request limit, never follows redirects, and records each request and response as evidence. |
303
+ | `src/apifuzz/checks/` | One module per check. `base.py` defines `Check`, `ScanContext` and the registry. |
304
+ | `src/apifuzz/scanner.py` | Runs the chosen checks over the chosen endpoints, and collects findings and coverage. |
305
+ | `src/apifuzz/finding.py` | The `Finding` record, its fingerprint, and the severity scale. |
306
+ | `src/apifuzz/report.py` | Shows results as tables, JSON or a standalone HTML report, redacted. |
307
+ | `src/apifuzz/docker_verify.py` | `--require-docker`: confirms each target is a running local container. |
308
+ | `src/apifuzz/cli.py` | The `apifuzz` command: `endpoints`, `checks`, `scan`, `verify-docker`. |
309
+ | `src/apifuzz/errors.py` | The error types shown to the user as plain messages. |
310
+ | `tests/` | Unit tests against a fake network, plus ground-truth scans of the real lab app in both modes. |
311
+
312
+ ## Develop
313
+
314
+ ```bash
315
+ ruff check .
316
+ pytest
317
+ ```
318
+
319
+ `uv.lock` pins the exact dependency versions; `uv sync --extra dev` installs from it.
320
+
321
+ The tests need no Docker: they run the lab app in-process and require exactly the lab table's
322
+ results from the normal lab and no findings from the hardened one. CI
323
+ ([.github/workflows/ci.yml](.github/workflows/ci.yml)) runs them on Linux and Windows for Python
324
+ 3.11 to 3.13, and also boots the real container and runs the demo scan.
325
+
326
+ ## Scope & ethics
327
+
328
+ Use this only on APIs you own or have written permission to test. The tool is built to make the
329
+ wrong thing hard: `scan` requires `--i-have-authorization`, the HTTP client enforces a host
330
+ allowlist, a spec cannot choose the target, and requests are capped. It detects flaws with
331
+ minimal requests and does not exploit them: probes use marker values, changes are put back, and
332
+ login attempts use an account that doesn't exist. It is not a tool for scanning third-party
333
+ services.
334
+
335
+ ## Releasing
336
+
337
+ Publishing to PyPI is automated by [.github/workflows/release.yml](.github/workflows/release.yml)
338
+ using PyPI Trusted Publishing (OIDC), so no API token is stored. One-time setup: register this
339
+ repo as a pending publisher at <https://pypi.org/manage/account/publishing/> (project `apifuzz`,
340
+ workflow `release.yml`, environment `pypi`), and create a GitHub environment named `pypi`. To cut
341
+ a release: bump `version` in `pyproject.toml` (PyPI refuses a re-upload of an existing version),
342
+ then publish a GitHub Release with a tag like `v0.2.0`. The workflow builds, runs `twine check`,
343
+ and uploads. The published version is the one in `pyproject.toml`, not the git tag.
344
+
345
+ ## What's next
346
+
347
+ - SARIF 2.1.0 output for GitHub code scanning, and a file of accepted findings.
348
+ - Wider injection coverage: path parameters and headers (today's check covers query-string
349
+ parameters and the JSON body fields of login/search endpoints, including a NoSQL operator-object
350
+ probe).
@@ -0,0 +1,25 @@
1
+ apifuzz/__init__.py,sha256=JNhmgeMYlhFM0-3krY3jIlqLrKZk6uaXv04LBJurmmM,609
2
+ apifuzz/__main__.py,sha256=BWtLcIQT2bwMxtYfti0jEXZ1md78lXHiKLTzBhNR2vU,279
3
+ apifuzz/cli.py,sha256=7oemRC9sy2osrxGO-37R2Ckj036oFcS8dj0VMazF614,19818
4
+ apifuzz/docker_verify.py,sha256=OPuwf0E7ga7GVgovNk0XhGbw0Qo7eMCe3Hryb1fbgZc,7361
5
+ apifuzz/endpoint_model.py,sha256=z7668JiFDqMYpDWlKN-XP063X3IWf_YXS60n0PUwR50,9416
6
+ apifuzz/errors.py,sha256=thoxTgqp-vfLXlrjdimPinOKLfZiUQyygBG8RR_lsRU,1395
7
+ apifuzz/finding.py,sha256=XwaD3HpM9u91M7vm-qCwSP9ak2n3udVPGjaJDZ8OoGY,2592
8
+ apifuzz/http_client.py,sha256=RSWUc9bgIyyi4HRWBQ6kHNmjKN_25Oy95rJvQBoIh7I,10574
9
+ apifuzz/report.py,sha256=tczGZXWnvpGQaccV6lzgntt03o8r87EBFqfBLOhzzjA,12512
10
+ apifuzz/scanner.py,sha256=hJI7OHIB44bmzoNRDYOwiCcyfMMedscPH0qni-LKpRY,4535
11
+ apifuzz/session_manager.py,sha256=ztsrPn5nQqe3ovlB8367tCJqA-nkPl9ve__G_zUBSfc,6994
12
+ apifuzz/settings.py,sha256=ueHCeWTllwCbB8I3TBeQvcI6jvovSd_NbRZ6a-mmU7I,12543
13
+ apifuzz/spec_loader.py,sha256=tPX39KVuduK_d0YEvyuDz53sXatpc8wAibzg4gmI68w,7877
14
+ apifuzz/checks/__init__.py,sha256=w8eHoQKbOd-9BQLDDB2j8S_DO4RG7lHY2zuPRhJMxDU,531
15
+ apifuzz/checks/auth_required.py,sha256=5_fWS3i-zF53WCie7JlUTX-klCp-B4gia1lae9UsNCo,3082
16
+ apifuzz/checks/base.py,sha256=cZDQop3x98_-TrbbC5f3hrtKgdLMk1Lj88gUuao01ug,7370
17
+ apifuzz/checks/bola.py,sha256=iN7od-ja1-7J26d5dC2TdrntwWsMbzUBs4LNg0dcDp8,16740
18
+ apifuzz/checks/injection.py,sha256=LWSyXv6ZsC12N1sz4hn4zb9uSzoqImhCcmgui4K-50I,14741
19
+ apifuzz/checks/mass_assignment.py,sha256=PAFbGJfV-YEKAcopzj-XB-MlHSvDEEH-AJnFBxlNWtc,14985
20
+ apifuzz/checks/rate_limit.py,sha256=C8rqVpuM_hMKN5AUE1D_5tQvMBjy0jn4W35b2h2ZSMk,8017
21
+ apifuzz-0.2.0.dist-info/METADATA,sha256=RMWBHzZiS-zQW8Y9aModXCOXLMwgxhbtv050e_BS6PE,20220
22
+ apifuzz-0.2.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
23
+ apifuzz-0.2.0.dist-info/entry_points.txt,sha256=j1qkWHvUbULFppoQx7dhSIHvJk4ijS00v6_Tfo4tM9g,44
24
+ apifuzz-0.2.0.dist-info/licenses/LICENSE,sha256=8uwFrQSotUOn5z1QVnrIaomXWf6gvNyFyoRTFErxVgs,1078
25
+ apifuzz-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.33.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ apifuzz = apifuzz.cli:app
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mateivarvara100-cloud
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.