Add fortiweb CVE 2025 64446 - #1490
Conversation
- Tests weak algorithms: sha1, md5, md2, md4 - Tests case insensitivity (uppercase input) - Tests safe algorithms: sha256, sha512, sha384 - Tests edge cases: empty string, random string - All 11 tests passing Part of improving test coverage for GSoC 2026
- TestIsSingleIPv4: 12 tests for IPv4 address validation - TestIsSingleIPv6: 10 tests including None bug documentation - TestIsIPv4Range: 8 tests (documents naming swap with is_ipv4_cidr) - TestIsIPv4CIDR: 7 tests (documents naming swap with is_ipv4_range) - TestIsIPv6Range: 6 tests for IPv6 dash-range detection - TestIsIPv6CIDR: 8 tests for IPv6 CIDR detection - TestGenerateIPRange: 7 tests covering both code branches - TestGetIPRange: 4 tests using unittest.mock for HTTP isolation Coverage: nettacker/core/ip.py 0% -> 83% Note: is_ipv4_range/is_ipv4_cidr and is_ipv6_range/is_ipv6_cidr appear to have swapped names - documented in test docstrings
CVE-2025-64446 is a critical (CVSS 9.8) relative path traversal in Fortinet FortiWeb WAF versions 8.0.1 and earlier. Unauthenticated attackers can traverse from /api/v2.0/ into the internal CGI handler to create admin accounts without credentials. Actively exploited since October 2025, added to CISA KEV catalog November 14 2025, fixed in FortiWeb 8.0.2. Detection sends a GET request to the traversal path and checks for 200 response or FortiWeb-specific content in the response body.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
Summary by CodeRabbit
WalkthroughA new vulnerability module for FortiWeb CVE-2025-64446 is introduced alongside documentation updates. The module detects a path traversal authentication bypass via HTTP requests across multiple ports and protocols. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
tests/core/lib/test_ssl.py (1)
10-58: Please restore targeted tests forget_cert_infoto avoid SSL coverage regression.This file now validates only
is_weak_hash_algo, whilenettacker/core/lib/ssl.py(Line 130-152) still contains non-trivial cert parsing/date computations (activation_date,expiring_soon,not_activated) that should remain tested.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/core/lib/test_ssl.py` around lines 10 - 58, Restore unit tests that target get_cert_info in nettacker/core/lib/ssl.py: add focused tests for the function get_cert_info that validate certificate parsing and the date-based flags activation_date, expiring_soon, and not_activated; create minimal certificate fixtures (or mock the parsed cert structure) for the following cases — already expired, not yet active, expiring within the threshold, and valid long-lived — and assert the returned activation_date, expiry date parsing and boolean flags match expectations; ensure tests reference get_cert_info and exercise the code paths around activation_date, expiring_soon, and not_activated so SSL-related coverage is preserved.tests/test_ip.py (1)
261-296:get_ip_rangesuccess path is documented but not tested.The docstring (Lines 264-266) says successful API behavior should be validated, but current tests only assert fallback/error paths. Please add one happy-path test with mocked RIPE response to lock in expected parsing behavior.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_ip.py` around lines 261 - 296, Add a happy-path unit test for get_ip_range that mocks nettacker.core.ip.requests.get to return a successful RIPE-style JSON payload and asserts the parsed result matches the expected list; specifically, patch requests.get to return an object whose .content is the RIPE API JSON string (matching the structure your production code parses), call get_ip_range("x.x.x.x") and compare the return to the expected output (either by calling generate_ip_range("x.x.x.x") or a hard-coded list), and ensure the test imports/uses the same get_ip_range and generate_ip_range symbols so it validates the success parsing path rather than only fallback behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@nettacker/modules/vuln/fortiweb_cve_2025_64446.yaml`:
- Around line 48-55: The rule currently uses condition_type: or so a match is
true if either status_code or content matches, which causes false positives due
to the broad "FortiWeb" token; change the logic to require both a valid HTTP
response and a fingerprint by setting condition_type to and and/or tighten the
content regex to require stronger indicators (e.g., combine tokens with
lookahead or require "fwbcgi" or "admin.*privilege" together with "FortiWeb") so
the rule only fires when status_code and content both match; update the YAML
fields condition_type, conditions -> status_code.regex, and conditions ->
content.regex accordingly.
In `@tests/test_ip.py`:
- Around line 1-296: The test file is placed at tests/test_ip.py but should
mirror the package layout; move this file to tests/core/test_ip.py so it aligns
with the module under test (nettacker.core.ip) and the project's test layout;
ensure the file name and imports (e.g., references to generate_ip_range,
get_ip_range, is_single_ipv4, etc.) remain unchanged after moving so pytest
discovery still runs the same tests.
- Around line 93-97: The test test_none_raises is too broad by catching
(TypeError, Exception); update the pytest.raises call in the test_none_raises
function to only expect TypeError so that only the documented failure from
is_single_ipv6(None) is accepted (replace the tuple with the single TypeError
exception).
---
Nitpick comments:
In `@tests/core/lib/test_ssl.py`:
- Around line 10-58: Restore unit tests that target get_cert_info in
nettacker/core/lib/ssl.py: add focused tests for the function get_cert_info that
validate certificate parsing and the date-based flags activation_date,
expiring_soon, and not_activated; create minimal certificate fixtures (or mock
the parsed cert structure) for the following cases — already expired, not yet
active, expiring within the threshold, and valid long-lived — and assert the
returned activation_date, expiry date parsing and boolean flags match
expectations; ensure tests reference get_cert_info and exercise the code paths
around activation_date, expiring_soon, and not_activated so SSL-related coverage
is preserved.
In `@tests/test_ip.py`:
- Around line 261-296: Add a happy-path unit test for get_ip_range that mocks
nettacker.core.ip.requests.get to return a successful RIPE-style JSON payload
and asserts the parsed result matches the expected list; specifically, patch
requests.get to return an object whose .content is the RIPE API JSON string
(matching the structure your production code parses), call
get_ip_range("x.x.x.x") and compare the return to the expected output (either by
calling generate_ip_range("x.x.x.x") or a hard-coded list), and ensure the test
imports/uses the same get_ip_range and generate_ip_range symbols so it validates
the success parsing path rather than only fallback behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e8722bb8-3d40-412a-959a-9af1df0dfdf2
📒 Files selected for processing (3)
nettacker/modules/vuln/fortiweb_cve_2025_64446.yamltests/core/lib/test_ssl.pytests/test_ip.py
…egex Addresses CodeRabbit feedback - using OR with broad FortiWeb token could cause false positives on any FortiWeb response regardless of vulnerability. Changed to AND requiring both HTTP 200 and specific content (super_admin, privilege, fwbcgi) to confirm vulnerable endpoint.
- tests/test_ip.py already exists at tests/core/test_ip.py, removed duplicate - tests/core/lib/test_ssl.py was accidentally stripped, restored 574-line original
|
Latest commits: tightened response matching to condition_type: and with stricter regex, removed tests/test_ip.py duplicate, restored SSL test suite. |
|
@Raavi29 you have failed to follow the guidelines and PR checks - there is no screenshot evidence proving the module works, documentation is not updated and your commits are not digitally signed. I recommend you learn to sign your commits first! Unsigned commits cannot be accepted! |
|
Closing this PR I was not aware of PR #1240 (in draft) which covers the same vulnerability. Apologies for the duplicate. Will review open and draft PRs more carefully before submitting new modules. |
Proposed change
Summary
Adds a new vulnerability detection module for CVE-2025-64446, a critical path traversal vulnerability in Fortinet FortiWeb WAF.
Vulnerability Details
How it works
FortiWeb's API handler forwards requests beginning with
/api/v2.0to a backend CGI handler before resolving path traversal sequences. An attacker sends a GET request to:/api/v2.0/cmdb/system/admin?/../../../../../cgi-bi/fwbcgiThis bypasses authentication entirely and reaches the internal
fwbcgiadministrative component.Detection
The module sends a GET request to the traversal path on ports 443, 8443, and 80 over both HTTP ad HTTPS. A vulnerability system returns HTTP 200 with FortiWeb-specific content. Patched systems (8.0.2+) return 403.
Refrences
Type of change
Checklist
make pre-commitand confirm it didn't generate any warnings/changesmake test, I confirm all tests passed locallydocs/folder