Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ OWASP Nettacker
OWASP Nettacker is an open-source, Python-based automated penetration testing and information-gathering framework designed to help cyber security professionals and ethical hackers perform reconnaissance, vulnerability assessments, and network security audits efficiently. Nettacker automates tasks like port scanning, service detection, subdomain enumeration, network mapping, vulnerability scanning, credential brute-force testing making it a powerful tool for identifying weaknesses in networks, web applications, IoT devices and APIs.

### Key Features

- **Modular architecture** - Each task — like port scanning, directory discovery, subdomain enumeration, vulnerability checks, or credential brute-forcing - is implemented as its own module, giving you control over what runs.
- **Multi-protocol & multithreaded scanning** - Supports HTTP/HTTPS, FTP, SSH, SMB, SMTP, ICMP, TELNET, XML-RPC, and can run scans in parallel for speed.
- **Comprehensive output** - Export reports in HTML, JSON, CSV, and plain text.
- **Built-in database & drift detection** - Stores past scans in the database for easy search and comparison with current results: useful to detect new hosts, open ports, or vulnerabilities in CI/CD pipelines.
- **CLI, REST API & Web UI** - Offers both programmatic integration and a user-friendly web interface for defining scans and viewing results.
- **Evasion techniques** - Enables configurable delays, proxy support, and randomized user-agents to reduce detection by firewalls or IDS systems.
- **Flexible targets** - Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs. Targets can be mixed in a single command or loaded from a file using the `-l/--targets-list` flag.
- **Flexible targets**: Accepts single IPv4s, IP ranges, CIDR blocks, domain names, and full HTTP/HTTPS URLs.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true but not for this PR.

These methods ensure full compatibility and avoid runtime errors

### Use Cases

Expand Down
28 changes: 27 additions & 1 deletion nettacker/core/arg_parser.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import difflib
import json
import sys
from argparse import ArgumentParser
Expand Down Expand Up @@ -518,7 +519,32 @@ def parse_arguments(self):
all ARGS with applied rules
"""
# Checking Requirements
options = self.api_arguments or self.parse_args()
if self.api_arguments:
options = self.api_arguments
else:
known_args, unknown_args = self.parse_known_args()

if unknown_args:
valid_flags = []
for action in self._actions:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self._actions is not defined anywhere. This code will break.

valid_flags.extend(action.option_strings)

for arg in unknown_args:
if arg.startswith("--") and len(arg) > 1:
suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
if suggestion:
print(
f"Error: Unknown argument '{arg}'. Did you mean '{suggestion[0]}'?",
file=sys.stderr,
)
else:
print(f"Error: Unknown argument '{arg}'", file=sys.stderr)
else:
print(f"Error: Unexpected argument '{arg}'", file=sys.stderr)
Comment on lines +536 to +543
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Localize the new CLI error messages.

These strings are hardcoded in English, so unknown-argument errors bypass the existing message catalog even though the CLI supports -L/--language. Please route them through _() / the normal failure path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nettacker/core/arg_parser.py` around lines 535 - 542, The three hardcoded
English messages printed for unknown/unexpected args should be routed through
the i18n catalog and the normal CLI failure path: replace the direct print(...)
calls that reference arg and suggestion (the branches using suggestion[0], the
else for "Unknown argument" and the "Unexpected argument" branch) so the message
strings are wrapped with _(...) and passed to the existing failure handler used
elsewhere (instead of raw print), e.g. build the localized message with
_("Error: Unknown argument '{arg}'. Did you mean '{suggestion}'?").format(...)
or _("Error: Unexpected argument '{arg}'").format(...) and forward that to the
same failure function or parser.error call used by the parser.


Comment on lines +532 to +544
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If an unknown argument is positional (doesn’t start with -), the code still exits with status 1 but prints no error message. Ensure all entries in unknown_args are surfaced to the user (positional and flags), ideally in a single consolidated message.

Suggested change
for arg in unknown_args:
if arg.startswith("-") and len(arg) > 1:
suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
if suggestion:
print(f"Error: Unknown argument '{arg}'. Did you mean '{suggestion[0]}'?")
else:
print(f"Error: Unknown argument '{arg}'")
error_messages = []
for arg in unknown_args:
# Flag-like unknown argument (starts with "-" and not just "-")
if arg.startswith("-") and len(arg) > 1:
suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
if suggestion:
error_messages.append(
f" {arg} (did you mean '{suggestion[0]}'?)"
)
else:
error_messages.append(f" {arg}")
# Positional unknown argument
else:
error_messages.append(f" {arg} (positional argument)")
if error_messages:
print(
"Error: Unknown arguments:\n" + "\n".join(error_messages)
)

Copilot uses AI. Check for mistakes.
sys.exit(1)

Comment on lines +532 to +546
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This path uses print(...) + sys.exit(1) for error handling, which bypasses the project’s existing die_failure() behavior (logging + color reset) and prints to stdout instead of stderr. Consider using die_failure(...) (or ArgumentParser.error(...) if you want argparse-style usage output) and include the suggestion text in that message.

Suggested change
for arg in unknown_args:
if arg.startswith("-") and len(arg) > 1:
suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
if suggestion:
print(f"Error: Unknown argument '{arg}'. Did you mean '{suggestion[0]}'?")
else:
print(f"Error: Unknown argument '{arg}'")
sys.exit(1)
error_messages = []
for arg in unknown_args:
if arg.startswith("-") and len(arg) > 1:
suggestion = difflib.get_close_matches(arg, valid_flags, n=1)
if suggestion:
error_messages.append(
f"Error: Unknown argument '{arg}'. Did you mean '{suggestion[0]}'?"
)
else:
error_messages.append(f"Error: Unknown argument '{arg}'")
if error_messages:
die_failure("\n".join(error_messages))

Copilot uses AI. Check for mistakes.
options = known_args
Comment on lines +525 to +547
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New behavior around unknown-argument detection/suggestion is introduced here, but there are no existing tests covering ArgParser behavior. Please add pytest coverage for cases like an unknown flag with a close match (suggestion emitted) and an unknown positional argument (error message emitted).

Copilot uses AI. Check for mistakes.

if options.language not in self.languages:
die_failure("Please select one of these languages {0}".format(self.languages))
Expand Down
Loading