granttrace 2.5.3__tar.gz → 2.7.0__tar.gz
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.
- granttrace-2.7.0/CHANGELOG.md +643 -0
- granttrace-2.7.0/CODE_OF_CONDUCT.md +83 -0
- granttrace-2.7.0/CONTRIBUTING.md +109 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/MANIFEST.in +5 -2
- granttrace-2.7.0/PKG-INFO +208 -0
- granttrace-2.7.0/README.md +181 -0
- granttrace-2.7.0/README.zh-CN.md +149 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/SECURITY.md +20 -9
- granttrace-2.7.0/VERIFICATION.md +426 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/api_sentinel.py +742 -633
- granttrace-2.7.0/config.schema.json +452 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/core/__init__.py +4 -4
- granttrace-2.7.0/core/auditor.py +1949 -0
- granttrace-2.7.0/core/authorization.py +212 -0
- granttrace-2.7.0/core/bopla.py +308 -0
- granttrace-2.7.0/core/config_scaffold.py +411 -0
- granttrace-2.7.0/core/config_validation/__init__.py +5 -0
- granttrace-2.7.0/core/config_validation/base.py +209 -0
- granttrace-2.7.0/core/config_validation/bola.py +336 -0
- granttrace-2.7.0/core/config_validation/identities.py +535 -0
- granttrace-2.7.0/core/config_validation/readbacks.py +621 -0
- granttrace-2.7.0/core/config_validation/spec_checks.py +248 -0
- granttrace-2.7.0/core/config_validator.py +215 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/core/demo.py +31 -9
- {granttrace-2.5.3 → granttrace-2.7.0}/core/diff.py +440 -172
- {granttrace-2.5.3 → granttrace-2.7.0}/core/evidence.py +184 -18
- {granttrace-2.5.3 → granttrace-2.7.0}/core/generator.py +156 -122
- {granttrace-2.5.3 → granttrace-2.7.0}/core/onboarding.py +1 -1
- {granttrace-2.5.3 → granttrace-2.7.0}/core/parameters.py +114 -16
- granttrace-2.7.0/core/parser.py +878 -0
- granttrace-2.7.0/core/remote_refs.py +873 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/core/reporter.py +748 -526
- {granttrace-2.5.3 → granttrace-2.7.0}/core/reproduction.py +35 -8
- granttrace-2.7.0/core/request_builder.py +699 -0
- granttrace-2.7.0/core/results.py +303 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/core/sarif.py +64 -2
- granttrace-2.7.0/core/scan_safety.py +214 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/core/transactions.py +69 -2
- granttrace-2.7.0/core/transport.py +158 -0
- granttrace-2.7.0/core/yaml_safety.py +98 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/docs/advanced.md +12 -5
- granttrace-2.7.0/docs/assets/report-finding.png +0 -0
- granttrace-2.7.0/docs/assets/report-preview.png +0 -0
- granttrace-2.7.0/docs/authorization-coverage-audit.md +282 -0
- granttrace-2.7.0/docs/bopla-readonly.md +59 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/docs/business-scenarios.md +1 -1
- granttrace-2.7.0/docs/case-studies/crapi.md +240 -0
- granttrace-2.7.0/docs/case-studies/vampi.md +253 -0
- granttrace-2.7.0/docs/comparison.md +81 -0
- granttrace-2.7.0/docs/configuration.md +332 -0
- granttrace-2.7.0/docs/parameter-serialization.md +38 -0
- granttrace-2.7.0/docs/pr42-independent-review.md +145 -0
- granttrace-2.7.0/docs/pr42-state-authority-review.md +98 -0
- granttrace-2.7.0/docs/pr43-integration-plan.md +66 -0
- granttrace-2.7.0/docs/pr43-integration-review.md +180 -0
- granttrace-2.7.0/docs/remote-references.md +123 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/docs/windows-portable.md +35 -17
- granttrace-2.7.0/examples/README.md +66 -0
- granttrace-2.7.0/examples/crapi/no-chatbot.compose.yml +10 -0
- granttrace-2.7.0/examples/crapi/prepare_config.py +185 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/examples/sample_report.html +157 -159
- {granttrace-2.5.3 → granttrace-2.7.0}/examples/sample_result.json +666 -647
- granttrace-2.7.0/examples/vampi/prepare_config.py +105 -0
- granttrace-2.7.0/examples/vampi/run_vampi.py +22 -0
- granttrace-2.7.0/granttrace.egg-info/PKG-INFO +208 -0
- granttrace-2.7.0/granttrace.egg-info/SOURCES.txt +178 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/pyproject.toml +76 -76
- {granttrace-2.5.3 → granttrace-2.7.0}/scripts/build_windows_portable.py +12 -5
- granttrace-2.7.0/scripts/source_version.py +86 -0
- granttrace-2.7.0/scripts/verify_authorization_coverage.py +335 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/scripts/verify_examples.py +46 -22
- {granttrace-2.5.3 → granttrace-2.7.0}/scripts/verify_install.py +10 -10
- granttrace-2.7.0/scripts/verify_pr42_adversarial.py +70 -0
- granttrace-2.7.0/scripts/verify_pr43_integration.py +275 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/scripts/verify_windows_portable.py +12 -3
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_auditor_integration.py +11 -1
- granttrace-2.7.0/tests/test_auth_cookie_references.py +312 -0
- granttrace-2.7.0/tests/test_auth_header_references.py +368 -0
- granttrace-2.7.0/tests/test_authorization_maintenance.py +184 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_authorization_policy_preflight.py +2 -2
- granttrace-2.7.0/tests/test_bopla_collection_grouping.py +67 -0
- granttrace-2.7.0/tests/test_bopla_integration.py +549 -0
- granttrace-2.7.0/tests/test_bopla_pending_exports.py +154 -0
- granttrace-2.7.0/tests/test_bopla_policy.py +212 -0
- granttrace-2.7.0/tests/test_bopla_policy_counterexamples.py +372 -0
- granttrace-2.7.0/tests/test_bopla_reports.py +190 -0
- granttrace-2.7.0/tests/test_bopla_transport_safety.py +296 -0
- granttrace-2.5.3/tests/test_rc2_security_hardening.py → granttrace-2.7.0/tests/test_cli_security_hardening.py +395 -395
- granttrace-2.7.0/tests/test_code_review_regressions.py +162 -0
- granttrace-2.7.0/tests/test_committed_examples.py +80 -0
- granttrace-2.7.0/tests/test_config_scaffold.py +433 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_curl_report.py +3 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_demo.py +24 -3
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_diff.py +1 -1
- granttrace-2.7.0/tests/test_english_reasons.py +128 -0
- granttrace-2.7.0/tests/test_expanded_detection.py +599 -0
- granttrace-2.7.0/tests/test_expanded_report_boundaries.py +90 -0
- granttrace-2.7.0/tests/test_header_cookie_array_object.py +1424 -0
- granttrace-2.7.0/tests/test_header_cookie_boundaries.py +177 -0
- granttrace-2.7.0/tests/test_header_cookie_parameters.py +991 -0
- granttrace-2.7.0/tests/test_header_cookie_transport.py +184 -0
- granttrace-2.7.0/tests/test_late_private_value_redaction.py +361 -0
- granttrace-2.7.0/tests/test_mass_assignment_flow.py +160 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_merge_patch_recovery.py +1 -0
- granttrace-2.7.0/tests/test_module_boundaries.py +80 -0
- granttrace-2.7.0/tests/test_not_found_denial.py +207 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_onboarding_cli.py +20 -2
- granttrace-2.7.0/tests/test_output_snapshot.py +167 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_parameter_serialization.py +13 -3
- granttrace-2.7.0/tests/test_parser_remote_refs.py +536 -0
- granttrace-2.7.0/tests/test_parser_replacement_auth.py +476 -0
- granttrace-2.5.3/tests/test_release_transactions.py → granttrace-2.7.0/tests/test_patch_readback_strictness.py +3 -0
- granttrace-2.7.0/tests/test_pr42_adversarial.py +396 -0
- granttrace-2.7.0/tests/test_pr42_state_authority.py +307 -0
- granttrace-2.7.0/tests/test_pr43_authorization_evidence.py +374 -0
- granttrace-2.7.0/tests/test_pr43_evidence_paths.py +77 -0
- granttrace-2.7.0/tests/test_pr43_put_safety.py +390 -0
- granttrace-2.7.0/tests/test_problem_details_denials.py +97 -0
- granttrace-2.7.0/tests/test_query_auth_parameters.py +173 -0
- granttrace-2.7.0/tests/test_rate_limit_retry.py +225 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_read_only_path_guards.py +8 -8
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_read_only_safety.py +2 -2
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_read_safety_cache.py +3 -3
- granttrace-2.7.0/tests/test_release_version.py +135 -0
- granttrace-2.7.0/tests/test_remote_ref_host_validation.py +205 -0
- granttrace-2.7.0/tests/test_remote_refs.py +557 -0
- granttrace-2.7.0/tests/test_remote_refs_hardening.py +1161 -0
- granttrace-2.7.0/tests/test_remote_refs_premerge_audit.py +397 -0
- granttrace-2.7.0/tests/test_remote_refs_review_hardening.py +251 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_sarif.py +8 -2
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_sarif_cli.py +24 -1
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_scan_accounting.py +1 -1
- granttrace-2.7.0/tests/test_small_review_items.py +213 -0
- granttrace-2.5.3/tests/test_v22_auditor_hardening.py → granttrace-2.7.0/tests/test_transaction_transport_hardening.py +3 -2
- granttrace-2.7.0/tests/test_transport.py +153 -0
- granttrace-2.7.0/tests/test_unconfigured_query_parameters.py +91 -0
- granttrace-2.7.0/tests/test_v27_features.py +1161 -0
- granttrace-2.7.0/tests/test_v27_hardening.py +680 -0
- granttrace-2.5.3/tests/test_release_identity.py → granttrace-2.7.0/tests/test_version_identity.py +26 -0
- granttrace-2.7.0/tests/test_yaml_alias_expansion.py +214 -0
- granttrace-2.5.3/CHANGELOG.md +0 -311
- granttrace-2.5.3/CONTRIBUTING.md +0 -65
- granttrace-2.5.3/PKG-INFO +0 -192
- granttrace-2.5.3/README.md +0 -165
- granttrace-2.5.3/VERIFICATION.md +0 -172
- granttrace-2.5.3/config.schema.json +0 -243
- granttrace-2.5.3/core/auditor.py +0 -1344
- granttrace-2.5.3/core/config_scaffold.py +0 -254
- granttrace-2.5.3/core/config_validator.py +0 -1590
- granttrace-2.5.3/core/parser.py +0 -519
- granttrace-2.5.3/core/scan_safety.py +0 -127
- granttrace-2.5.3/docs/assets/report-preview.png +0 -0
- granttrace-2.5.3/docs/configuration.md +0 -143
- granttrace-2.5.3/docs/parameter-serialization.md +0 -19
- granttrace-2.5.3/examples/README.md +0 -36
- granttrace-2.5.3/granttrace.egg-info/PKG-INFO +0 -192
- granttrace-2.5.3/granttrace.egg-info/SOURCES.txt +0 -98
- granttrace-2.5.3/tests/test_config_scaffold.py +0 -197
- {granttrace-2.5.3 → granttrace-2.7.0}/LICENSE +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/config.example.json +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/core/demo_assets/__init__.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/core/demo_assets/demo-config.json +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/core/demo_assets/mock-data.json +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/core/demo_assets/openapi.json +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/core/models.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/docs/authorization-audit-hardening.md +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/docs/history/release-checklist-history.md +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/docs/history/release-verification-history.md +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/docs/release-checklist.md +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/granttrace.egg-info/dependency_links.txt +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/granttrace.egg-info/entry_points.txt +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/granttrace.egg-info/requires.txt +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/granttrace.egg-info/top_level.txt +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/mock_server/__init__.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/mock_server/server.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/openapi.json +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/scripts/benchmark_read_safety.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/scripts/verify_business_scenarios.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/setup.cfg +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/test_suite.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_authorization_evidence_hardening.py +0 -0
- /granttrace-2.5.3/tests/test_release_bola.py → /granttrace-2.7.0/tests/test_bola_rejection_evidence.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_business_authorization.py +0 -0
- /granttrace-2.5.3/tests/test_rc3_hardening.py → /granttrace-2.7.0/tests/test_cli_config_preflight.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_cli_report_boundaries.py +0 -0
- /granttrace-2.5.3/tests/test_release_config.py → /granttrace-2.7.0/tests/test_config_readback_preflight.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_config_validation.py +0 -0
- /granttrace-2.5.3/tests/test_release_evidence.py → /granttrace-2.7.0/tests/test_credential_echo_redaction.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_diff_hardening.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_evidence.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_first_run_guidance.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_onboarding.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_parameter_compatibility.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_parser_generator_hardening.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_report_usability.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_reproduction.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_schema_regressions.py +0 -0
- {granttrace-2.5.3 → granttrace-2.7.0}/tests/test_spec_config_cross_checks.py +0 -0
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2.7.0 - 2026-11-11
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- BOLA on query-style POST operations. A POST is sent only when its `bola`
|
|
8
|
+
policy declares `read_only: true` and gives the request body; its path,
|
|
9
|
+
operationId or summary must name a read action (search, query, lookup...)
|
|
10
|
+
and none of its metadata or concrete path may name a mutation. `body` is
|
|
11
|
+
sent unchanged by every identity; `identity_bodies` gives the Owner body
|
|
12
|
+
(repeated by the Visitor's cross request and Anonymous) and an optional
|
|
13
|
+
`visitor_self` body. Anything else is skipped or inconclusive with zero
|
|
14
|
+
requests, and a rate-limited POST is never retried.
|
|
15
|
+
- Sensitive-field leads (`detect_sensitive_exposure`, OWASP API3): unmasked
|
|
16
|
+
sensitive-named Owner values that reach the Visitor at the same JSON path.
|
|
17
|
+
`CONFIRMED` only with an explicit `deny` policy, a confirmed object-level
|
|
18
|
+
decision on the same observations and a value that differs from the
|
|
19
|
+
Visitor's own record; otherwise `SUSPICIOUS`. Values are never reported,
|
|
20
|
+
and the analysis is bounded on untrusted responses.
|
|
21
|
+
- Role matrix (`identities.roles`): for operations with a `required_role`,
|
|
22
|
+
one request per configured role, decided with the BFLA evidence standard
|
|
23
|
+
(valid privileged baseline, clean Anonymous denial, configured protected
|
|
24
|
+
data in the role's valid response). Shown in the HTML report and the JSON
|
|
25
|
+
`rbac_matrix`; confirmed violations are exported to SARIF as `GT-BFLA-001`,
|
|
26
|
+
confirmed sensitive-field findings as `GT-BOPLA-001`.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- The Windows portable build, its verifier, its workflow and the packaged
|
|
31
|
+
README and launcher read the version from `pyproject.toml` and
|
|
32
|
+
`core/__init__.py` (checked to agree) instead of repeating it. A test fails
|
|
33
|
+
on any drift.
|
|
34
|
+
|
|
35
|
+
## 2.6.0 - 2026-11-09
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- Read-only Broken Authentication (CWE-306, SARIF `GT-AUTH-001`) and Broken
|
|
40
|
+
Function Level Authorization (CWE-285, `GT-BFLA-001`) checks, and private-data
|
|
41
|
+
checks for collection endpoints (CWE-639). Confirmation requires explicitly
|
|
42
|
+
configured `private_data_paths` and role policy; names and keywords alone stay
|
|
43
|
+
leads (#43).
|
|
44
|
+
- PUT mass-assignment checks that use complete replacement snapshots and verified
|
|
45
|
+
rollback. Like PATCH, they run only with independent authoritative resource
|
|
46
|
+
state, which only internal test fixtures provide (the bundled demo tests
|
|
47
|
+
PATCH); external CLI targets stay blocked before any write (#43).
|
|
48
|
+
- Evidence-bound read-only property authorization (BOPLA, CWE-200) driven by
|
|
49
|
+
explicit per-operation `bopla` field rules and resource bindings (#44).
|
|
50
|
+
- GET header and cookie parameters, including header arrays and objects, sent
|
|
51
|
+
from `parameter_values`; authentication headers and cookies stay
|
|
52
|
+
identity-scoped and cookie arrays/objects are rejected under RFC 6265
|
|
53
|
+
(#45, #46). Swagger 2 header values are validated before transport (#47).
|
|
54
|
+
- Opt-in remote `$ref` resolution over HTTPS (`--allow-remote-refs` with
|
|
55
|
+
`--remote-ref-host`): exact host allowlist, SSRF and DNS-rebinding defences,
|
|
56
|
+
no redirects, size/count/depth/time limits, and no fetching in offline modes.
|
|
57
|
+
See [docs/remote-references.md](docs/remote-references.md) (#48).
|
|
58
|
+
- `--init-config` drafts the remaining inputs a scan needs, as placeholders
|
|
59
|
+
that still block validation until replaced. Required GET business headers and
|
|
60
|
+
cookies get one value per requesting identity (owner, visitor and anonymous)
|
|
61
|
+
in `parameter_values`; required authentication headers go to owner's and
|
|
62
|
+
visitor's `identities.*.headers`, and required authentication cookies to their
|
|
63
|
+
`identities.*.parameters` (#74 stopped drafting optional authentication
|
|
64
|
+
headers). PUT operations get parameter values and a readback
|
|
65
|
+
draft like PATCH, with the extra PUT rules in the checklist. Optional
|
|
66
|
+
parameters, ignored headers such as `Accept` and unsupported cookie forms
|
|
67
|
+
are not drafted, and the checklist says why for each. A draft completed with
|
|
68
|
+
real values now plans every drafted GET check, where previously its required
|
|
69
|
+
headers and cookies were missing. The checklist no longer marks parameters of
|
|
70
|
+
operations GrantTrace does not test, such as DELETE, as included in the
|
|
71
|
+
draft (#73).
|
|
72
|
+
- A case study of a scan of VAmPI, a deliberately vulnerable API, in its
|
|
73
|
+
vulnerable and secure modes: which of its vulnerabilities GrantTrace confirms,
|
|
74
|
+
which it misses and why, and the request log of the read-only scan. Helper
|
|
75
|
+
scripts in `examples/vampi/` reproduce it. See
|
|
76
|
+
[docs/case-studies/vampi.md](docs/case-studies/vampi.md) (#81).
|
|
77
|
+
- `bola.<operation>.not_found_is_denial` reads a 404 as a denial, for APIs
|
|
78
|
+
that hide other users' objects with "not found" instead of 403. A Visitor or
|
|
79
|
+
Anonymous 404 counts only when the Owner received a valid response to the
|
|
80
|
+
same request, the body is empty or only says the object was not found (a
|
|
81
|
+
full-message grammar with at most one word naming the resource type, in a
|
|
82
|
+
known error envelope or Problem Details), and none of the Owner's values
|
|
83
|
+
appears in it; any other 404 keeps its default meaning, `INCONCLUSIVE`.
|
|
84
|
+
BOLA, Broken Authentication, BFLA and collection checks of the operation
|
|
85
|
+
apply it; BOPLA field rules do not. A 404 denial gives `SECURE` with
|
|
86
|
+
confidence 0.95, below an explicit 401 or 403, and the evidence records the
|
|
87
|
+
setting. Secure-mode VAmPI's book lookup now reports `SECURE` instead of
|
|
88
|
+
`INCONCLUSIVE` (#82).
|
|
89
|
+
- The VAmPI case study confirms the debug endpoint's password exposure with a
|
|
90
|
+
BOPLA field rule: the Owner's password in `/users/v1/_debug` may be read by
|
|
91
|
+
the Owner only, although the specification leaves the endpoint open, so both
|
|
92
|
+
the Visitor and Anonymous results are `CONFIRMED` (`GT-BOPLA-001`) in both
|
|
93
|
+
modes. `examples/vampi/prepare_config.py --debug-field-rule` writes the rule;
|
|
94
|
+
it runs as a separate scan because BOPLA's privacy boundary omits response
|
|
95
|
+
details from the whole report. The configuration guide now points to field
|
|
96
|
+
rules for private fields on operations without an authentication
|
|
97
|
+
requirement (#83).
|
|
98
|
+
- A case study of a read-only scan of OWASP crAPI 1.1.6: GrantTrace confirms
|
|
99
|
+
another user's mechanic report (challenge 2), the order lookup without
|
|
100
|
+
authentication (challenge 14), an administrator user list any user can read,
|
|
101
|
+
and, with BOPLA field rules, post authors' email addresses and vehicle IDs
|
|
102
|
+
(challenge 4). Challenge 1 stays `SUSPICIOUS` because crAPI's identity service
|
|
103
|
+
answers requests without a token with a Java `toString()` instead of JSON.
|
|
104
|
+
`examples/crapi/` holds the setup script and a Compose override that runs
|
|
105
|
+
crAPI without its chatbot. See
|
|
106
|
+
[docs/case-studies/crapi.md](docs/case-studies/crapi.md) (#85).
|
|
107
|
+
- A comparison of GrantTrace's approach with Autorize, AuthMatrix, ZAP's Access
|
|
108
|
+
Control Testing add-on and Akto, from their documentation: where requests come
|
|
109
|
+
from, what is expected, how a result is decided, and when another tool fits
|
|
110
|
+
better. It compares approaches, not detection rates. See
|
|
111
|
+
[docs/comparison.md](docs/comparison.md) (#86).
|
|
112
|
+
|
|
113
|
+
### Changed
|
|
114
|
+
|
|
115
|
+
- Synchronize package, runtime, Windows distribution and release-workflow
|
|
116
|
+
versions to `2.6.0`, a minor release for the checks and options added since
|
|
117
|
+
2.5.3. The remote `$ref` fetcher's User-Agent now follows the runtime version
|
|
118
|
+
instead of a hard-coded `2.5.3`. Refresh release documentation and the example
|
|
119
|
+
reports.
|
|
120
|
+
- Rewrite the README as an English project page, with a Chinese translation in
|
|
121
|
+
`README.zh-CN.md`: what GrantTrace does and a quick start first, a table of the
|
|
122
|
+
checks with what each needs, and a plain list of what is not supported. Mass
|
|
123
|
+
assignment is described as demo-only, as it is for external APIs. The report
|
|
124
|
+
screenshot is retaken from the 2.6.0 demo, a confirmed-finding screenshot is
|
|
125
|
+
added, and the README no longer states a release status that each release had
|
|
126
|
+
to update. Chinese documentation links back to the Chinese README (#79).
|
|
127
|
+
- Report BOLA reasons in English, like every other check. The JSON `reason`,
|
|
128
|
+
finding `details` and per-response `reason` evidence of BOLA checks were the
|
|
129
|
+
only Chinese reasons; the HTML report shows the same text. Verdicts,
|
|
130
|
+
`reason_category` and evidence fields are unchanged, and Chinese denial
|
|
131
|
+
messages returned by a target API are still recognized. Consumers that
|
|
132
|
+
matched the Chinese text should match the verdict or `reason_category`.
|
|
133
|
+
Offline validation messages no longer append a Chinese note. The HTML
|
|
134
|
+
report's interface text stays Chinese (#57).
|
|
135
|
+
- Store every text file with LF line endings (`.gitattributes` now normalizes
|
|
136
|
+
them; the Windows portable build still writes CRLF for its batch launcher),
|
|
137
|
+
and name 13 test modules after the behavior they cover instead of the PR or
|
|
138
|
+
release that added them. No runtime change (#58).
|
|
139
|
+
- Regenerate the example reports in `examples/` from the built-in demo. They
|
|
140
|
+
were still the 2.5.3 output, with Chinese BOLA reasons and without the newer
|
|
141
|
+
statistics, and showed PATCH results that a CLI scan of an external target no
|
|
142
|
+
longer produces, because such scans stop PATCH checks before any write.
|
|
143
|
+
`scripts/verify_examples.py --update-examples` now copies a fresh
|
|
144
|
+
`granttrace demo` run after verifying the CLI scans, and a new test fails when
|
|
145
|
+
the committed examples no longer match a fresh demo run. No runtime change (#70).
|
|
146
|
+
|
|
147
|
+
### Performance
|
|
148
|
+
|
|
149
|
+
- Parse each response once and reuse comparison data in BOLA evaluation, cache
|
|
150
|
+
key normalization, precompile evidence scrubbing patterns and skip redundant
|
|
151
|
+
path resolution while resolving schemas. Outputs are unchanged; on 150 KB
|
|
152
|
+
responses and 300-operation specifications these paths run about twice as
|
|
153
|
+
fast (#50).
|
|
154
|
+
- Reuse response assessments across BOPLA field rules: ten rules on a 496 KB
|
|
155
|
+
response took 271 ms and now take 14 ms, with identical decisions (#55).
|
|
156
|
+
|
|
157
|
+
### Fixed
|
|
158
|
+
|
|
159
|
+
- Recognize RFC 9457 (RFC 7807) Problem Details bodies as clean 401/403 denials.
|
|
160
|
+
connexion sends them as `application/problem+json`, for example `{"type":
|
|
161
|
+
"about:blank", "title": "Unauthorized", "status": 401, "detail": "No
|
|
162
|
+
authorization token provided"}`, and ASP.NET Core and Spring can be configured
|
|
163
|
+
to. GrantTrace treated these members as possible business data, so a scan of
|
|
164
|
+
VAmPI, a deliberately vulnerable API, reported its book BOLA as `SUSPICIOUS`
|
|
165
|
+
instead of `CONFIRMED`, and Broken Authentication on its protected reads as
|
|
166
|
+
`INCONCLUSIVE` instead of `SECURE`: the anonymous denial could not serve as a
|
|
167
|
+
clean baseline. A problem body now counts as a denial only when every member
|
|
168
|
+
is `type`, `title`, `status`, `detail` or a tracing ID, `status` is 401 or
|
|
169
|
+
403, `type` is `about:blank` or an HTTP RFC status link, and `title` and
|
|
170
|
+
`detail` are denial messages. Any other member or text keeps it suspicious,
|
|
171
|
+
including `instance`: the check does not know the request path, so it cannot
|
|
172
|
+
tell whether the URI names the requested resource or another user's. Ordinary
|
|
173
|
+
JSON envelopes also accept a numeric `status` of 401 or 403 and messages such
|
|
174
|
+
as "No authorization token provided" (#80).
|
|
175
|
+
- Refuse checks of operations that send a credential in the query string, before
|
|
176
|
+
any request. Each URL is built from the resource owner's parameter values and
|
|
177
|
+
sent by every identity, so an `apiKey` scheme `in: query` (or the RFC 6750
|
|
178
|
+
`access_token` parameter) made the visitor and anonymous requests carry the
|
|
179
|
+
owner's key: against a correctly secured API they appeared to read the owner's
|
|
180
|
+
resource, giving false `SUSPICIOUS` or `CONFIRMED` results. Such checks are now
|
|
181
|
+
`INCONCLUSIVE` (`invalid_input`) with a reason saying query-string credentials
|
|
182
|
+
are not supported, and `--init-config` no longer drafts them as resource
|
|
183
|
+
parameters. Ordinary query parameters, including names such as `page_token`,
|
|
184
|
+
are unaffected (#75).
|
|
185
|
+
- Stop refusing GET checks over an optional authentication header that neither
|
|
186
|
+
owner nor visitor configures. A header parameter classified as authentication
|
|
187
|
+
(for example `X-Session-Id`, or an API-key scheme's header) blocked the check
|
|
188
|
+
as `INCONCLUSIVE` unless both identities sent it, even when the specification
|
|
189
|
+
marks it optional, and the reason wrongly said a value was "supplied via
|
|
190
|
+
parameter values". It is now omitted, like an optional authentication cookie.
|
|
191
|
+
A value from `parameter_values` and a header configured for only one of owner
|
|
192
|
+
and visitor are still refused, and a missing required one is refused with a
|
|
193
|
+
reason that says to configure it under `identities.*.headers` (#74).
|
|
194
|
+
- Stop sending invented values for optional query parameters that nobody
|
|
195
|
+
configured. Every declared query parameter got a generated value, so a scan
|
|
196
|
+
could request `?as_user=sample_text&status=active&include_deleted=false`:
|
|
197
|
+
such values can filter out the tested resource, make the target reject the
|
|
198
|
+
request or change its behavior, so the comparison no longer measured
|
|
199
|
+
authorization. An unconfigured optional query parameter is now omitted, or
|
|
200
|
+
sent with its declared `default`, as header and cookie parameters already
|
|
201
|
+
were. Required parameters and resource identifiers such as `owner_id` keep
|
|
202
|
+
their previous values (#76).
|
|
203
|
+
- Use an identity's `id` for its resource parameter exactly or not at all.
|
|
204
|
+
Lenient integer parsing turned `"007"`, `"1_001"` or `" 1002 "` into 7, 1001
|
|
205
|
+
or 1002, and an id outside the schema (such as `"abc"`, or `"0"` below a
|
|
206
|
+
minimum) was silently replaced by the specification's example value, so the
|
|
207
|
+
check tested a resource the Owner does not own. Such ids now follow the
|
|
208
|
+
canonical rules of `parameter_values`, and a check that cannot use them is
|
|
209
|
+
`INCONCLUSIVE` (`invalid_input`) before any request (#55).
|
|
210
|
+
- Ignore non-string media types instead of crashing with `AttributeError`, for
|
|
211
|
+
example a Swagger 2 `consumes: [123, "application/json"]` (#55).
|
|
212
|
+
- Reject header parameter values with leading or trailing whitespace, which
|
|
213
|
+
servers strip inconsistently, so the tested value always matches the
|
|
214
|
+
configured one; whitespace inside a value is still allowed (#55).
|
|
215
|
+
- Publish secret values discovered while building request headers by atomic
|
|
216
|
+
replacement. The in-place update raced with evidence sanitization in other
|
|
217
|
+
workers and could drop a value from later redaction (#50).
|
|
218
|
+
- Report the specific "without precision loss" diagnostic for number parameter
|
|
219
|
+
strings instead of the generic message that replaced it (#50).
|
|
220
|
+
- Require TLS 1.2 or later for remote schema fetches (#50).
|
|
221
|
+
- Retry rate-limited reads instead of recording them as inconclusive. GET
|
|
222
|
+
requests answered with HTTP 429 (or 503 with `Retry-After`) are retried up
|
|
223
|
+
to twice, honoring `Retry-After` in seconds or as an HTTP date (otherwise
|
|
224
|
+
waiting 1 s, then 2 s), and every worker pauses meanwhile. A requested wait
|
|
225
|
+
beyond 30 s fails closed with the original response. PATCH/PUT are never
|
|
226
|
+
retried. The new `rate_limit_retries` statistic counts retries; a scan of
|
|
227
|
+
the bundled mock target that rate-limits each path's first request now
|
|
228
|
+
reaches the same verdicts as an unlimited one (#53).
|
|
229
|
+
- Enforce the remote `$ref` fetch timeout as an absolute deadline. Socket
|
|
230
|
+
timeouts applied per receive, so a server dripping header or body bytes held
|
|
231
|
+
a 0.3 s fetch for 3 s or longer; a close-delimited body cut off at the
|
|
232
|
+
deadline is no longer accepted as complete (#52).
|
|
233
|
+
- Reject remote documents that end before their declared Content-Length, and
|
|
234
|
+
turn malformed HTTP responses and over-nested JSON into per-reference
|
|
235
|
+
resolution failures instead of errors that aborted the whole scan (#52).
|
|
236
|
+
- Check the IPv4 destination embedded in 6to4, Teredo and NAT64 addresses and
|
|
237
|
+
block IPv4-compatible, local-use NAT64 and site-local IPv6 ranges. CPython
|
|
238
|
+
releases before its 2024 `ipaddress` update (e.g. 3.9.19, 3.12.3) treated
|
|
239
|
+
6to4 addresses embedding 169.254.169.254 or 127.0.0.1 as global (#52).
|
|
240
|
+
- Report a path item whose remote `$ref` fails as `INCONCLUSIVE`
|
|
241
|
+
(`unresolved_reference`), as documented, instead of a skipped "UNKNOWN"
|
|
242
|
+
method that `--fail-on-error` did not count (#52).
|
|
243
|
+
- Reject `--remote-ref-host` values that can never match a `$ref` URL host:
|
|
244
|
+
a scheme, port, path, credentials, wildcard, whitespace, non-ASCII
|
|
245
|
+
characters (use the IDNA form) or an empty value. Such values were accepted
|
|
246
|
+
and then authorized nothing, so every remote reference failed later as
|
|
247
|
+
"not in the authorized allowlist". The CLI exits 2 and names the value. IPv6
|
|
248
|
+
literals are compared in canonical form, with or without brackets.
|
|
249
|
+
- Bound YAML anchor/alias expansion in local specifications, referenced YAML
|
|
250
|
+
files and remote `$ref` documents. A ~1 KB alias "bomb" previously stalled
|
|
251
|
+
parsing for 13 s or more (merge keys inside `yaml.safe_load` itself); aliases
|
|
252
|
+
may now add at most max(250,000, 10 x the document's own nodes) nodes, and
|
|
253
|
+
recursive aliases are rejected before any object is built or request is sent (#51).
|
|
254
|
+
- Fail closed before external CLI PATCH tests when authoritative resource state
|
|
255
|
+
cannot be independently observed; write flags, mappings and a declared strong
|
|
256
|
+
readback cannot supply that proof. Existing CLI/config syntax remains accepted.
|
|
257
|
+
- Check initial, post-write and restored HTTP documents against actual backing
|
|
258
|
+
state in the owned disposable Demo. Retain global write halt on unavailable
|
|
259
|
+
or contradictory restoration evidence, including queued concurrent callers.
|
|
260
|
+
- Preserve and retest both original unmarked-cache counterexamples; distinguish
|
|
261
|
+
generic HTTP blocking from state-backed fixture detection statistics.
|
|
262
|
+
|
|
263
|
+
- PR #42 follow-up review: reject explicitly aged/stale state evidence, require
|
|
264
|
+
previously observed business structure before confirming persistence, and
|
|
265
|
+
serialize direct write-audit calls so waiting callers observe recovery failures.
|
|
266
|
+
- Add independent adversarial regressions and disclose two unresolved unmarked
|
|
267
|
+
stale-response probes; distinguish statement, branch and combined code coverage.
|
|
268
|
+
- Require complete HTTP 200 JSON state readbacks without Content-Range before
|
|
269
|
+
using them as PATCH snapshots, persistence evidence or restoration evidence.
|
|
270
|
+
Preserve generic write acknowledgement handling, recovery and fail-closed write halting.
|
|
271
|
+
- Retain strong Owner-object matches in 4xx/5xx response bodies as suspicious
|
|
272
|
+
leads only, without changing confirmation or SARIF export requirements.
|
|
273
|
+
- Include explicitly readOnly fields with ordinary names in mutation candidates;
|
|
274
|
+
configured field mappings, write opt-in, allowlists and reversible snapshots still gate execution.
|
|
275
|
+
- Prefer a declared JSON consumes format for Swagger 2 bodies and explain more
|
|
276
|
+
existing preflight exclusions in offline plans.
|
|
277
|
+
- Add fixed-truth loopback acceptance scenarios, regression tests and a source-linked
|
|
278
|
+
capability audit with before/after measurements. No new vulnerability class is implemented.
|
|
279
|
+
|
|
280
|
+
### Maintenance
|
|
281
|
+
|
|
282
|
+
- Restructure the largest modules and functions without changing behavior
|
|
283
|
+
(#59 to #69). Snapshot tests of the JSON, HTML and console output of mock-target
|
|
284
|
+
scans came first and passed unchanged through the series; a deliberate output
|
|
285
|
+
change regenerates them with `GRANTTRACE_UPDATE_SNAPSHOTS=1` (#59).
|
|
286
|
+
`core/auditor.py` shrank from 2283 to 1499 lines: HTTP transport moved to
|
|
287
|
+
`core/transport.py`, request construction to `core/request_builder.py`, and
|
|
288
|
+
result recording and coverage to `core/results.py` (#61, #62, #63).
|
|
289
|
+
`core/config_validator.py` shrank from 1735 to 250 lines: its checks moved to
|
|
290
|
+
the `core/config_validation/` package, one module per configuration section,
|
|
291
|
+
and `ConfigValidator` and its result types are still imported from
|
|
292
|
+
`core.config_validator` (#65). The mass-assignment check, request header
|
|
293
|
+
construction, readback validation, schema value validation, the CLI `main`,
|
|
294
|
+
BOLA evaluation and the HTML report were split into smaller steps (#62, #63,
|
|
295
|
+
#64, #66, #67, #68, #69). Moved code is unchanged apart from names. Most
|
|
296
|
+
splits were compared with the previous code over large random inputs, and the
|
|
297
|
+
CLI over 34 command lines, with identical results; new tests cover the
|
|
298
|
+
per-field branches of the mass-assignment check. The seven hash-pinned write
|
|
299
|
+
methods are untouched, and a new test fails if production code uses another
|
|
300
|
+
module's private member (#60).
|
|
301
|
+
- Split `ConfigValidator.validate` (220 lines) into named steps with one
|
|
302
|
+
section runner instead of five copies of the same error handling. A
|
|
303
|
+
differential run over 40,000 mutated configurations gave identical results
|
|
304
|
+
(#77).
|
|
305
|
+
- Code that imports `core` directly needs these changes; the CLI and
|
|
306
|
+
`granttrace demo` are unaffected:
|
|
307
|
+
- Helpers used across modules lost their leading underscore, and the old
|
|
308
|
+
names were removed: `ResponseDiffEngine.assess_response`,
|
|
309
|
+
`assessment_evidence`, `normalise_key`, `is_request_metadata_key` and
|
|
310
|
+
`denial_body_is_clean`; `AuthorizationEvidence.assess`, `valid`,
|
|
311
|
+
`private_values` and `clean_denial`; `SmartDataGenerator.parameter_schema`
|
|
312
|
+
and `is_resource_identifier`; `APISentinelAuditor.identity_headers`. The new
|
|
313
|
+
`APISentinelAuditor.secret_values()` returns an immutable snapshot of the
|
|
314
|
+
published secrets (#60).
|
|
315
|
+
- `RETRYABLE_METHODS`, `RATE_LIMIT_RETRIES`, `RATE_LIMIT_BACKOFF` and
|
|
316
|
+
`MAX_RETRY_WAIT` moved from `APISentinelAuditor` to
|
|
317
|
+
`core.transport.HttpTransport`. The redirect handler is
|
|
318
|
+
`core.transport.NoRedirectHandler` (was `core.auditor._NoRedirectHandler`),
|
|
319
|
+
and the auditor's opener is `_transport.opener` (was `_opener`) (#61).
|
|
320
|
+
- `request_delay`, `request_timeout` and `max_response_bytes` are read-only
|
|
321
|
+
properties of `APISentinelAuditor`. Pass them to the constructor: assigning
|
|
322
|
+
them afterwards raises `AttributeError` (#61).
|
|
323
|
+
- `_http_request` and `_authoritative_patch_state` are documented extension
|
|
324
|
+
points and keep their names and signatures (#60).
|
|
325
|
+
- Documentation: the v2.5.3 post-release acceptance records (#36 to #41), user
|
|
326
|
+
documentation synced with merged behavior (#54), the contributing guide's
|
|
327
|
+
output checks (#72) and the first release-preparation record (#78). Before
|
|
328
|
+
release, SECURITY.md, the command-line reference and the configuration guide
|
|
329
|
+
now state that write checks against an external target stop before any write;
|
|
330
|
+
the package description no longer lists mass assignment, which only the
|
|
331
|
+
built-in demo performs; the command-line reference documents `--workers` and
|
|
332
|
+
`--timeout`; a Code of Conduct (Contributor Covenant 2.1) is added; and the
|
|
333
|
+
Windows guide describes the released state (#87).
|
|
334
|
+
|
|
335
|
+
## 2.5.3 - 2026-10-15
|
|
336
|
+
|
|
337
|
+
### Fixed
|
|
338
|
+
|
|
339
|
+
- [PR #33](https://github.com/ysc070528/granttrace/pull/33): recognize complete
|
|
340
|
+
authentication and permission denial messages, including JWT denials, without
|
|
341
|
+
treating rejected responses containing business data as clean denials. Explain
|
|
342
|
+
Owner, Visitor self-resource and Anonymous evidence and missing prerequisites;
|
|
343
|
+
retain conservative BOLA / IDOR confirmation requirements.
|
|
344
|
+
- Validate selected BOLA policies before HTTP requests and accept the existing
|
|
345
|
+
`items[].id` trusted-evidence selector syntax in configuration validation.
|
|
346
|
+
- Count actual transport attempts and distinct method/path operations for
|
|
347
|
+
attempted and conclusive coverage. Exclude zero-request preflight outcomes
|
|
348
|
+
and recovery rows from endpoint coverage; explain skip and evidence categories
|
|
349
|
+
in reports. `SUSPICIOUS` and `INCONCLUSIVE` remain non-conclusive.
|
|
350
|
+
- Apply read-only side-effect checks using operation identifiers, paths,
|
|
351
|
+
summaries and descriptions during BOLA preflight, dry-run planning and final
|
|
352
|
+
HTTP execution. Reject unsafe independent readbacks before any PATCH.
|
|
353
|
+
- [PR #34](https://github.com/ysc070528/granttrace/pull/34): validate each concrete
|
|
354
|
+
GET / HEAD path, including the target base path, before route-cache lookup and
|
|
355
|
+
transport. Reject ambiguous encodings, invalid UTF-8, dot/matrix-dot segments,
|
|
356
|
+
repeated slashes, boundary encoded slashes, backslashes and control characters.
|
|
357
|
+
Apply the same guard to BOLA, offline plans and PATCH readbacks without rewriting
|
|
358
|
+
URLs; ordinary supported encoded identifiers remain supported.
|
|
359
|
+
|
|
360
|
+
### Changed
|
|
361
|
+
|
|
362
|
+
- Reuse cached immutable read-safety metadata and route patterns from PR #33
|
|
363
|
+
while continuing to validate every concrete URL before requests.
|
|
364
|
+
- Synchronize package, runtime, Windows distribution and release-workflow
|
|
365
|
+
versions to `2.5.3`; refresh release documentation and generated loopback
|
|
366
|
+
examples. This release preparation introduces no new detector or API behavior.
|
|
367
|
+
|
|
368
|
+
Static read-safety checks do not prove that every GET is harmless. Verification
|
|
369
|
+
scope and remaining post-release acceptance are recorded in [VERIFICATION.md](VERIFICATION.md).
|
|
370
|
+
|
|
371
|
+
## 2.5.2 - 2026-10-05
|
|
372
|
+
|
|
373
|
+
### Maintenance
|
|
374
|
+
|
|
375
|
+
- Documentation / distribution metadata maintenance release: package the current
|
|
376
|
+
README for the PyPI project page, retaining the corrected Windows download,
|
|
377
|
+
unsigned-program notice, macOS / Linux installation and workflow explanation.
|
|
378
|
+
- Align package/runtime versions and Windows portable filenames, launcher,
|
|
379
|
+
bundled instructions and release workflow metadata at `2.5.2`.
|
|
380
|
+
- No changes to BOLA / IDOR / Mass Assignment detection, the security model,
|
|
381
|
+
default read-only behavior, CLI semantics or core implementation.
|
|
382
|
+
|
|
383
|
+
## 2.5.1 - 2026-10-05
|
|
384
|
+
|
|
385
|
+
### Fixed
|
|
386
|
+
|
|
387
|
+
- Reject unsafe Merge Patch probes before writes when the original state cannot be restored exactly.
|
|
388
|
+
- Preserve array record associations during BOLA comparison to avoid overstating confirmed authorization bypasses.
|
|
389
|
+
- Harden report target/metadata redaction for known credentials and prevent report outputs from overwriting specification, configuration, or loaded local `$ref` inputs.
|
|
390
|
+
- Improve local and conditional schema resolution plus configuration-to-spec operation validation.
|
|
391
|
+
- Preserve legacy v2.5.0 scalar parameter configurations while applying strict schema-aware normalization and validation for canonical integer, number, and boolean values.
|
|
392
|
+
- Preserve Swagger 2.0 `uniqueItems` parameter constraints during schema extraction so duplicate configured arrays fail validation before requests.
|
|
393
|
+
|
|
394
|
+
## 2.5.0 - 2026-10-04
|
|
395
|
+
|
|
396
|
+
### Added
|
|
397
|
+
|
|
398
|
+
- Export SARIF 2.1.0 with `--export-sarif`, alongside HTML and JSON reports.
|
|
399
|
+
Only existing CONFIRMED findings produce results: BOLA / IDOR maps to
|
|
400
|
+
`GT-BOLA-001` / `CWE-639`, and Mass Assignment to `GT-MASS-001` / `CWE-915`.
|
|
401
|
+
A safely represented OpenAPI file inside the workspace supplies the artifact
|
|
402
|
+
location for GitHub Code Scanning; no source lines or endpoint files are invented.
|
|
403
|
+
- Add safe cURL reproduction templates and copy buttons to confirmed HTML finding
|
|
404
|
+
cards. Use the actual tested URL and confirmed injected payload where safe,
|
|
405
|
+
Visitor credential placeholders, POSIX shell quoting and `curl --globoff`.
|
|
406
|
+
Clipboard fallback supports offline reports; manual selection works without
|
|
407
|
+
JavaScript. Real credentials never enter the templates, including when sensitive
|
|
408
|
+
report evidence is enabled.
|
|
409
|
+
- Guide configuration onboarding from draft generation and manual review through
|
|
410
|
+
validation, a local dry-run and a read-only first real scan. Distinguish
|
|
411
|
+
config-only from spec-aware validation, summarize dry-run counts, and format
|
|
412
|
+
next-step commands safely for POSIX shells or PowerShell.
|
|
413
|
+
|
|
414
|
+
### Changed
|
|
415
|
+
|
|
416
|
+
- Align README, configuration and advanced guidance with the first API onboarding
|
|
417
|
+
flow and the SARIF / cURL outputs, without changing configuration formats.
|
|
418
|
+
- Explain validation scope, warnings and dry-run write eligibility more clearly.
|
|
419
|
+
An active PATCH configuration is separate from enabling active execution;
|
|
420
|
+
the recommended first real scan remains read-only.
|
|
421
|
+
- Promote the release source to `2.5.0` across package metadata, runtime version
|
|
422
|
+
and generated examples; prepare the release checklist and OIDC workflow for
|
|
423
|
+
the new tag without publishing it during release preparation.
|
|
424
|
+
|
|
425
|
+
### Security / Safety
|
|
426
|
+
|
|
427
|
+
- Preserve BOLA / IDOR verdicts and Mass Assignment detection criteria, default
|
|
428
|
+
read-only auditing, and the existing TLS / HTTP / redirect / proxy boundaries.
|
|
429
|
+
- Active PATCH still requires explicit `--allow-write-tests`, an explicit write
|
|
430
|
+
allowlist, independent GET readback, original-state snapshots, rollback and
|
|
431
|
+
rollback verification. Failed recovery still halts further writes.
|
|
432
|
+
- SARIF, cURL templates and onboarding output do not expose real credentials;
|
|
433
|
+
onboarding also omits configured resource values. Workspace-external specs
|
|
434
|
+
never expose absolute local paths in SARIF.
|
|
435
|
+
- Validation and dry-run remain offline; dry-run sends zero requests. No active
|
|
436
|
+
POST / PUT testing or automated OAuth / login is added.
|
|
437
|
+
|
|
438
|
+
### Quality
|
|
439
|
+
|
|
440
|
+
- Retain the 486-test baseline, Python 3.9 / 3.12 / 3.14 CI, blocking mypy and Ruff,
|
|
441
|
+
Runtime dependency audit, CodeQL and the branch-aware coverage gate of 80%.
|
|
442
|
+
- Fresh release-prep acceptance passes all 486 tests with **82.78%** branch-aware
|
|
443
|
+
local coverage, mypy reporting no issues in 18 source files, Ruff and the runtime
|
|
444
|
+
dependency audit. All six bundled business scenarios match their expected
|
|
445
|
+
outcomes; JSON / YAML scans restore the full mock database. A fresh wheel
|
|
446
|
+
installed outside the checkout passes both demo modes and verifies version
|
|
447
|
+
`2.5.0`, read-only 0 PATCH, active rollback and local server shutdown. See
|
|
448
|
+
[VERIFICATION.md](VERIFICATION.md) for the exact scope and remote check results.
|
|
449
|
+
|
|
450
|
+
## 2.4.1 - 2026-10-03
|
|
451
|
+
|
|
452
|
+
### Added
|
|
453
|
+
|
|
454
|
+
- Add `granttrace demo` with packaged OpenAPI, configuration and fictional mock
|
|
455
|
+
data, so an installed wheel can demonstrate identity comparison, BOLA / IDOR,
|
|
456
|
+
Mass Assignment, independent readback and rollback verification outside a Git
|
|
457
|
+
checkout without user credentials or external API access.
|
|
458
|
+
- Start the disposable mock on a dynamic loopback port, close it on completion
|
|
459
|
+
or failure, and retain HTML / JSON reports in a unique output directory.
|
|
460
|
+
- Add `--output-dir` and optional `--read-only` controls for the built-in demo.
|
|
461
|
+
|
|
462
|
+
### Changed
|
|
463
|
+
|
|
464
|
+
- Put the single-command installed-package demo before the source-checkout
|
|
465
|
+
walkthrough and retain configuration onboarding and safety boundaries. During
|
|
466
|
+
release preparation, distinguish the upcoming package from the published stable
|
|
467
|
+
version and do not claim an unpublished PyPI release is available.
|
|
468
|
+
- Give missing spec/config files and offline configuration failures a concise
|
|
469
|
+
next step; an empty write allowlist still sends no PATCH requests.
|
|
470
|
+
- Promote the 2.4.1.dev0 development package to 2.4.1 consistently across runtime,
|
|
471
|
+
package metadata and generated reports; update the release acceptance checklist.
|
|
472
|
+
|
|
473
|
+
### Quality
|
|
474
|
+
|
|
475
|
+
- Resolve the existing 20 mypy errors in six files using accurate annotations and
|
|
476
|
+
type narrowing, without new suppression directives or weaker mypy settings.
|
|
477
|
+
- Make mypy a blocking CI check and add a minimum 80% branch-aware coverage gate.
|
|
478
|
+
- Add weekly Dependabot checks for pip dependencies and GitHub Actions, without
|
|
479
|
+
automatic merging; exclude the release workflow from dependency updates.
|
|
480
|
+
- Verify installed demo resources, source-independent startup, both demo modes,
|
|
481
|
+
complete database restoration and local server shutdown.
|
|
482
|
+
|
|
483
|
+
### Security / Safety
|
|
484
|
+
|
|
485
|
+
- The demo accepts no external target or user credentials. Its active PATCH checks
|
|
486
|
+
run only against bundled, disposable data on a dynamic `127.0.0.1` server.
|
|
487
|
+
- Keep auditing users' own APIs read-only by default; `granttrace demo --read-only`
|
|
488
|
+
sends no PATCH requests.
|
|
489
|
+
- Preserve the BOLA / IDOR and Mass Assignment detection criteria, explicit write
|
|
490
|
+
allowlists, independent GET readback, original-state snapshots and rollback
|
|
491
|
+
verification. Failed recovery still blocks subsequent writes.
|
|
492
|
+
- Keep the existing `granttrace --spec ...` CLI, TLS / HTTP / redirect / proxy
|
|
493
|
+
safety boundaries and evidence minimisation unchanged.
|
|
494
|
+
|
|
495
|
+
## 2.4.0 - 2026-10-03
|
|
496
|
+
|
|
497
|
+
### Added
|
|
498
|
+
|
|
499
|
+
- Generate offline OpenAPI configuration drafts and missing-input checklists;
|
|
500
|
+
reject unresolved drafts and refuse to overwrite existing files.
|
|
501
|
+
- Add offline HTML report search/status filters and compact severity labels.
|
|
502
|
+
- Support strict OpenAPI style/explode and Swagger collectionFormat parameter
|
|
503
|
+
serialization in scans/readbacks, including arrays and lowercase booleans;
|
|
504
|
+
decline unsupported or ambiguous formats before sending requests.
|
|
505
|
+
- Add explicit per-pair expected_visitor_access for legitimate sharing/admin
|
|
506
|
+
reads, recorded as AUTHORIZED, and six local authorization truth fixtures with
|
|
507
|
+
false-positive/false-negative accounting.
|
|
508
|
+
- Add mandatory Ruff checks, real unittest branch coverage with text/XML/JSON
|
|
509
|
+
evidence, runtime dependency auditing with pip-audit, and a Python CodeQL
|
|
510
|
+
workflow. Keep mypy advisory while recording existing type debt.
|
|
511
|
+
- Add simple issue templates and contribution guidance with private vulnerability
|
|
512
|
+
reporting and reminders to exclude credentials and sensitive target data.
|
|
513
|
+
|
|
514
|
+
### Changed
|
|
515
|
+
|
|
516
|
+
- Promote the previously identified 2.4.0.dev0 development build to 2.4.0 across
|
|
517
|
+
runtime, package metadata and reports; retain api_sentinel.py and
|
|
518
|
+
APISentinelAuditor compatibility.
|
|
519
|
+
- Use granttrace_report.html when no output path is supplied and align package
|
|
520
|
+
description, version status and GrantTrace branding.
|
|
521
|
+
- Keep a concise five-minute README walkthrough, add identity/readback/restoration
|
|
522
|
+
highlights, and preserve the visible report preview and detailed guide links.
|
|
523
|
+
- Explain identity/resource access, changed fields, restoration and next steps
|
|
524
|
+
before raw evidence. JSON report schema is version 2.
|
|
525
|
+
- Remove tests' dependence on untracked config.json; automate JSON/YAML mock
|
|
526
|
+
restoration and clean wheel installation outside the checkout in CI.
|
|
527
|
+
- Maintain reproducible release verification and local-output ignore rules;
|
|
528
|
+
remove an unused demo image while preserving the report preview.
|
|
529
|
+
- Include example configuration, guides and verification scripts in the source
|
|
530
|
+
distribution so its documented local checks can be reproduced.
|
|
531
|
+
|
|
532
|
+
### Security / Safety
|
|
533
|
+
|
|
534
|
+
- Preserve default read-only auditing and explicit allowlisted JSON PATCH checks;
|
|
535
|
+
active POST/PUT checks and automated authentication are not added.
|
|
536
|
+
- Preserve independent GET readback, original-state snapshots, finally-protected
|
|
537
|
+
restoration and rollback verification. Failed recovery halts subsequent writes.
|
|
538
|
+
- Preserve TLS verification by default, explicit non-loopback HTTP opt-in and
|
|
539
|
+
minimized/redacted evidence by default.
|
|
540
|
+
- Retain denial, anonymous-leak and invalid-baseline boundaries without changing
|
|
541
|
+
the BOLA / IDOR or Mass Assignment detection criteria during release preparation.
|
|
542
|
+
|
|
543
|
+
Historical release tags and assets, including v2.3.1, remain unchanged.
|
|
544
|
+
|
|
545
|
+
## 2.3.1 - Verified authorization, snapshot and credential fixes
|
|
546
|
+
|
|
547
|
+
- Require trustworthy, clean anonymous rejection before a visitor-denial branch
|
|
548
|
+
can produce endpoint-level SECURE; leaked business data remains suspicious.
|
|
549
|
+
- Reject non-standard JSON constants and overflowing floats in response parsing.
|
|
550
|
+
Validate the original snapshot and finite request payloads before any PATCH;
|
|
551
|
+
preserve recovery when a post-write readback is invalid.
|
|
552
|
+
- Redact component values from request Cookie headers, including names such as
|
|
553
|
+
path/domain/secure/version, quoted/encoded echoes and known numeric credentials.
|
|
554
|
+
- Align readback parameter arrays, elements and override mappings between the
|
|
555
|
+
editor schema, semantic validator and runtime.
|
|
556
|
+
- Load the same JSON/YAML specification authentication context in configuration
|
|
557
|
+
validation and scanning; reject explicit invalid specifications cleanly.
|
|
558
|
+
- Validate the effective CLI write allowlist against its own readback mappings.
|
|
559
|
+
- Add 45 regression tests across four release modules; all 223 tests pass with
|
|
560
|
+
real PyYAML installed. Repeat complete CLI mock audits for JSON and YAML and
|
|
561
|
+
confirm full database restoration.
|
|
562
|
+
- Build/install the 2.3.1 wheel and smoke-test its installed console entry point;
|
|
563
|
+
refresh sample reports and record current verification separately from history.
|
|
564
|
+
|
|
565
|
+
## 2.3.0 (v2.3.0-final) - Configuration validation, authoritative identity rules, and release hardening
|
|
566
|
+
|
|
567
|
+
- **Authoritative Configuration Validator (`core/config_validator.py`)**:
|
|
568
|
+
- Implemented offline semantic validation engine for `config.json` without external network requests.
|
|
569
|
+
- Added `--validate-config` CLI flag for pre-flight validation (exit code 0 for valid, 2 for invalid), without target-network requests or state-changing target actions.
|
|
570
|
+
- Normal CLI scanning automatically runs the authoritative preflight check, rejecting invalid configurations before creating the auditor or sending any HTTP requests.
|
|
571
|
+
- Enforced single canonical format for operation keys (`<METHOD> /<path>` with strictly single space), consistent case handling, and spelling error suggestions (Levenshtein distance).
|
|
572
|
+
- Implemented symmetric two-way path collision detection (`paths_collide`) between `ignore_readback_paths` and written/readback paths across both validator and transaction rollback.
|
|
573
|
+
- Unified authentication header recognition rules between Validator and Auditor, standardizing `session`, `credential`, custom `auth_header_names`, and OpenAPI-declared security schemes.
|
|
574
|
+
|
|
575
|
+
- **Schema and Exemplary Assets**:
|
|
576
|
+
- Added standard `config.schema.json` (JSON Schema Draft-07) for editor autocomplete, hover documentation, and structural validation.
|
|
577
|
+
- Added comprehensive `config.example.json` with `$schema` linkage, sample identities, readbacks, and BOLA policies.
|
|
578
|
+
|
|
579
|
+
- **Security and Robustness Hardening**:
|
|
580
|
+
- Bound recursion depth (`MAX_RECURSION_DEPTH = 15`) and explicitly reject non-standard JSON numeric values (`NaN`, `Infinity`).
|
|
581
|
+
- Strict credential sanitization across all diagnostic outputs (`Actual`, `Expected`, errors) and stripped CR/LF/control characters to mitigate known log-injection paths.
|
|
582
|
+
|
|
583
|
+
- **Core Detection Behavior Compatibility**:
|
|
584
|
+
- No intentional behavior changes were made to BOLA decisions, snapshot recovery, diff, generator, or parser logic in this release; all existing regression tests continue to pass.
|
|
585
|
+
|
|
586
|
+
- **Test Suite Expansion**:
|
|
587
|
+
- Total automated tests expanded from 118 to 178 (all 178 passing, 0 failures, 0 errors).
|
|
588
|
+
- Added 22 offline configuration validation tests (`tests/test_config_validation.py`).
|
|
589
|
+
- Added 20 security and sanitization tests (`tests/test_rc2_security_hardening.py`).
|
|
590
|
+
- Added 18 strict regression counterexample tests (`tests/test_rc3_hardening.py`).
|
|
591
|
+
|
|
592
|
+
- **Packaging Hygiene and Metadata**:
|
|
593
|
+
- Standardized Python package version in `pyproject.toml` to PEP 440 compliant `2.3.0`, with GitHub / ZIP delivery tag designated as `v2.3.0-final`.
|
|
594
|
+
- Purged all build artifacts, temporary test reports (`API_Security_Report.html`, `result.json`), and caches (`__pycache__`, `*.pyc`, `.pytest_cache`, `.git`) from the distribution archive.
|
|
595
|
+
|
|
596
|
+
## 2.2.0 - Regression-driven safety fixes
|
|
597
|
+
|
|
598
|
+
- Snapshot/recover complete written fields, objects and arrays using original
|
|
599
|
+
business values; compare the full readback state, including derived changes.
|
|
600
|
+
- Recover after mutation/readback exceptions, guard recovery's own exceptions,
|
|
601
|
+
and stop later writes on failed verification or asynchronous acceptance.
|
|
602
|
+
- Require configured strong readback consistency for unchanged-write SECURE.
|
|
603
|
+
- Do not mistake 403-with-data, historical denial text, anonymous private
|
|
604
|
+
increments, or undeclared public access for access-control enforcement.
|
|
605
|
+
- Compare effective authentication headers; exclude request/trace echoes from
|
|
606
|
+
identity evidence and support explicit trusted response resource_id_paths.
|
|
607
|
+
- Probe readOnly privilege fields while excluding them from ordinary baselines.
|
|
608
|
+
- Recursively validate samples, intersect allOf constraints and reject invalid
|
|
609
|
+
baselines. Resolve 3.1 ref siblings in their original contexts; reject ambiguous
|
|
610
|
+
3.0/Swagger structural siblings and missing pointers instead of losing fields.
|
|
611
|
+
- Propagate supported media types, rejecting unsupported JSON Patch arrays.
|
|
612
|
+
- Bound/redact bodies, URLs, known credentials, error text and result metadata.
|
|
613
|
+
- Add zero-check CI failure, coverage/suspicious gates, no-network dry-run and
|
|
614
|
+
case-sensitive CLI allowlist replacement.
|
|
615
|
+
|
|
616
|
+
Migration: PUBLIC needs explicit policy; unchanged active checks need strong
|
|
617
|
+
readback consistency. Rewrite 3.0 structural ref siblings as allOf. Full-state
|
|
618
|
+
verification may require explicitly identifying harmless volatile fields. These
|
|
619
|
+
checks do not establish a universal rollback or privacy guarantee.
|
|
620
|
+
|
|
621
|
+
## 2.1.0 - Safety hardening
|
|
622
|
+
|
|
623
|
+
- Made read-only auditing the default and limited active mutations to explicitly
|
|
624
|
+
allowlisted JSON `PATCH` operations.
|
|
625
|
+
- Added independent read-before/write/read-after/rollback verification, retrying
|
|
626
|
+
readback and treating asynchronous or ambiguous outcomes as errors.
|
|
627
|
+
- Reworked BOLA decisions around owner, cross-visitor, anonymous, and distinct
|
|
628
|
+
visitor-self baselines. Matching JSON structure alone is never confirmation.
|
|
629
|
+
- Added explicit `CONFIRMED`, `SECURE`, `PUBLIC`, `SUSPICIOUS`, `INCONCLUSIVE`,
|
|
630
|
+
`SKIPPED`, and `ERROR` results with honest attempted/conclusive coverage.
|
|
631
|
+
- Enabled TLS verification by default, blocked redirects, capped response sizes,
|
|
632
|
+
added global throttling, and restricted non-loopback clear-text HTTP.
|
|
633
|
+
- Added default evidence minimisation, secret/PII redaction, hashes, and HTML
|
|
634
|
+
escaping.
|
|
635
|
+
- Expanded OpenAPI parsing to JSON/YAML, safe local external references,
|
|
636
|
+
recursive schemas/compositions, and parameter override semantics.
|
|
637
|
+
- Added constraint-aware parameters, valid request baselines, and one-field
|
|
638
|
+
nested mass-assignment mutations.
|
|
639
|
+
- Added packaging metadata, CI, an Apache-2.0 license, security guidance, and a
|
|
640
|
+
standard-library regression suite.
|
|
641
|
+
|
|
642
|
+
The bundled mock remains intentionally vulnerable in one BOLA route and one
|
|
643
|
+
mass-assignment route so the end-to-end flow can be verified safely on loopback.
|