Skip to main content

DefendKing

A defensive-only Python security toolkit (~70 functions across 9 sections) covering passwords, phishing/URL safety, brute-force protection, file hygiene, web-app security, network checks, cryptography, monitoring/ reporting, and API/session security.

Every function protects, detects, or reports — none of them attack, exploit, or access systems you don't own/manage.

Author: Barman License: MIT Current version: 2.5.1


Table of contents


Install

pip install defendking                # core package, no third-party deps required
pip install "defendking[full]"        # adds requests / cryptography / pyjwt for the
                                       # functions that call external APIs or do AES/JWT
pip install "defendking[dev]"         # adds pytest for running the test suite

For local development (editable install from a clone):

pip install -e ".[full,dev]"
python -m pytest tests/ -v

Quick start

import defendking as dk

result = dk.check_password_strength("Tr0ub4dor&3")
print(result)
# {'score': 64, 'label': 'medium', 'entropy_bits': 65.4, 'suggestions': [...]}

url_check = dk.check_suspicious_url("http://192.168.1.1@paypal-login.tk/verify")
print(url_check["suspicious"], url_check["risk_score"])
# True 85

Everything is also importable by name:

from defendking import check_password_strength, generate_strong_password

Error handling

DefendKing follows one consistent rule everywhere (see defendking.exceptions):

  • Programmer errors (wrong argument type, empty required value, value out of range) raise InvalidInputError immediately. Catch it like:
    from defendking import InvalidInputError
    try:
        dk.generate_strong_password(length=2)
    except InvalidInputError as e:
        print("bad input:", e)
    
  • External-world failures (network down, DNS failed, file missing):
    • Functions that already return a dict report the failure inside that dict — error / error_type: "ExternalServiceError" — and do not raise.
      result = dk.check_ssl_certificate("unreachable-host.example")
      if not result["valid"]:
          print(result["error"])
      
    • Functions whose normal return is a plain scalar (a hash string, a bool) raise ExternalServiceError instead, since silently turning their return type into a dict would break every call site.
      from defendking import ExternalServiceError
      try:
          dk.compute_file_hash("missing.txt")
      except ExternalServiceError as e:
          print("could not hash file:", e)
      

Every function's docstring says explicitly which behavior applies to it.


1. Passwords & authentication

check_password_strength(password: str) -> dict

Scores a password 0-100 using length, character diversity, estimated entropy (bits), and known weak-pattern detection.

dk.check_password_strength("correct horse battery staple 42!")
# {'score': 100, 'label': 'strong', 'entropy_bits': 112.8, 'suggestions': []}

check_password_breached(password: str, use_api: bool = True) -> dict

Checks a password against Have I Been Pwned (k-anonymity model — only a hash prefix is sent) with a local-list fallback.

dk.check_password_breached("123456")
# {'breached': True, 'times_seen': 37810483, 'source': 'hibp'}

generate_strong_password(length: int = 16, use_symbols: bool = True) -> str

dk.generate_strong_password(20)
# 'xQ2!kP9$mZr7@vLwT4nB'

hash_password(password: str) -> str / verify_password(password, stored_hash) -> bool

PBKDF2-HMAC-SHA256 password hashing with a random salt.

stored = dk.hash_password("my secret password")
dk.verify_password("my secret password", stored)   # True
dk.verify_password("wrong guess", stored)           # False

detect_common_password_patterns(password: str) -> list[str]

Flags keyboard walks, sequences, repeats, dates, and leetspeak substitutions.

dk.detect_common_password_patterns("Qwerty123")
# ['Contains a keyboard-walk pattern', 'Likely contains a birth year or date']

check_two_factor_status(is_enabled_flag: bool, backup_codes_count: int = 0) -> dict

dk.check_two_factor_status(True, backup_codes_count=1)
# {'enabled': True, 'has_backup_codes': True, 'low_on_backup_codes': True, 'recommendation': 'Good posture'}

check_password_expiry(last_changed: datetime, max_age_days: int = 90) -> dict

from datetime import datetime, timedelta, timezone
dk.check_password_expiry(datetime.now(timezone.utc) - timedelta(days=95))
# {'age_days': 95, 'max_age_days': 90, 'expired': True, ...}

validate_password_policy_compliance(password: str, policy: dict = None) -> dict

dk.validate_password_policy_compliance("alllowercase")
# {'compliant': False, 'violations': ['An uppercase letter is required', ...]}

check_default_credentials(username: str, password: str) -> bool

dk.check_default_credentials("admin", "admin")   # True

2. Phishing & URL/email safety

check_suspicious_url(url: str) -> dict

Regex/heuristic phishing signal detection with a weighted risk_score (0-100): raw IPs, punycode, homograph domains, open-redirect params, brand impersonation, and more.

dk.check_suspicious_url("http://192.168.1.1@paypal-login.tk/verify")
# {'suspicious': True, 'risk_score': 100, 'reasons': [...]}

check_domain_similarity(domain: str, trusted_domains: list[str]) -> dict

Typosquat detection via Levenshtein distance, homoglyph normalization (rnm, 1l, ...), substring spoofing, and TLD-swap detection.

dk.check_domain_similarity("paypa1.com", ["paypal.com"])
# {'likely_typosquat': True, 'matched_via_homoglyph_normalization': True, ...}

check_ssl_certificate(hostname: str, port: int = 443, timeout: float = 5.0) -> dict

dk.check_ssl_certificate("example.com")
# {'valid': True, 'expires': '...', 'days_until_expiry': 62, 'expiring_soon': False}

scan_email_for_phishing_signs(email_text: str) -> dict

Weighted-score scan for urgency language, credential harvesting, unusual payment requests, BEC/executive-impersonation patterns, and more.

dk.scan_email_for_phishing_signs("Dear customer, act now and click here to verify your account: http://bit.ly/xyz")
# {'suspicious': True, 'risk_score': 60, 'reasons': [...]}

extract_and_check_links(text: str) -> list[dict]

dk.extract_and_check_links("Check this out: http://bit.ly/xyz")
# [{'url': 'http://bit.ly/xyz', 'suspicious': True, ...}]

validate_email_format_and_mx(email: str, check_mx: bool = True) -> dict

dk.validate_email_format_and_mx("test@example.com", check_mx=False)
# {'email': 'test@example.com', 'valid_format': True, 'has_mx_record': None, 'is_disposable_domain': False}

3. Brute-force / abuse protection

RateLimiter(max_attempts=5, window_seconds=300)

limiter = dk.RateLimiter(max_attempts=3, window_seconds=60)
limiter.allow("1.2.3.4")   # True, True, True, then False on the 4th call
limiter.reset("1.2.3.4")   # clear after a successful login

rate_limiter(key, store, max_attempts=5, window_seconds=300) -> bool

Functional variant for callers managing their own storage dict.

detect_brute_force_attempt(failed_timestamps: list[float], threshold=5, window_seconds=60) -> bool

dk.detect_brute_force_attempt([t, t+1, t+2, t+3, t+4], threshold=5, window_seconds=60)
# True

IPBlocklist()

blocklist = dk.IPBlocklist()
blocklist.block("10.0.0.1", duration_seconds=900)
blocklist.is_blocked("10.0.0.1")   # True
blocklist.unblock("10.0.0.1")

implement_captcha_trigger(failed_attempts, threshold=3, window_seconds=None, failed_timestamps=None) -> bool

dk.implement_captcha_trigger(failed_attempts=3, threshold=3)   # True

log_failed_login_attempt(username, ip, log_path="failed_logins.csv") -> dict

dk.log_failed_login_attempt("baduser", "1.2.3.4")
# {'success': True, 'path': 'failed_logins.csv'}

distance_km_between(lat1, lon1, lat2, lon2) -> float

Haversine great-circle distance.

dk.distance_km_between(35.6892, 51.3890, 40.7128, -74.0060)
# 9877.5 (Tehran to New York, km)

detect_anomalous_login_location(previous_country, new_country, previous_time, new_time, previous_coords=None, new_coords=None) -> dict

"Impossible travel" detector.

dk.detect_anomalous_login_location(
    "IR", "US", t1, t2,
    previous_coords=(35.6892, 51.3890), new_coords=(40.7128, -74.0060),
)
# {'anomalous': True, 'high_confidence': True, 'implied_speed_kmh': 118530.0, ...}

detect_privilege_escalation_attempt(role_before, role_after, allowed_transitions: dict) -> bool

dk.detect_privilege_escalation_attempt("viewer", "admin", {"viewer": {"editor"}})
# True (not an allowed transition)

4. File / malware hygiene

compute_file_hash(filepath, algorithm="sha256") -> str

dk.compute_file_hash("report.pdf")
# 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3...'

scan_file_hash_virustotal(filepath, api_key) -> dict

Looks up a file's hash on VirusTotal (does not upload the file).

detect_suspicious_file_extension(filename: str) -> dict

Flags dangerous extensions, double extensions, RTL-override tricks, and padded/hidden extensions.

dk.detect_suspicious_file_extension("invoice.pdf.exe")
# {'flagged': True, 'double_extension_trick': True, ...}

check_file_integrity(filepath, known_good_hash, algorithm="sha256") -> bool

dk.check_file_integrity("backup.zip", "a94a8fe5...")

scan_directory_for_malware_signatures(directory, signatures: dict) -> list[dict]

dk.scan_directory_for_malware_signatures("/downloads", {"a94a8f...": "known_trojan_x"})

quarantine_suspicious_file(filepath, quarantine_dir="./quarantine") -> str

dk.quarantine_suspicious_file("suspicious.exe")
# './quarantine/1735689600_suspicious.exe.quarantined'

verify_backup_integrity(backup_path, expected_hash) -> bool


5. Web application security

sanitize_user_input(user_input: str) -> str

dk.sanitize_user_input("<script>alert(1)</script>")
# '&lt;script&gt;alert(1)&lt;&#x2F;script&gt;'

generate_csrf_token() -> str / check_csrf_token_validity(request_token, session_token) -> bool

validate_cors_policy(allowed_origins: list[str], request_origin: str) -> dict

dk.validate_cors_policy(["*"], "https://example.com")
# {'allowed': True, 'warning': "Using '*' together with credentials is a security risk", ...}

detect_xss_patterns(input_text: str) -> list[str]

Covers <script>, event handlers, javascript:/vbscript:, data: URIs, meta-refresh, entity/unicode encoding, template-literal injection, and more.

dk.detect_xss_patterns("<img src=x onerror=alert(1)>")
# ['inline event handler (...)', '<img> tag with onerror handler']

check_secure_cookie_flags(set_cookie_header: str) -> dict

dk.check_secure_cookie_flags("session=abc; SameSite=None")
# {'httponly': False, 'secure': False, 'samesite': True, 'samesite_none_without_secure': True}

validate_input_against_sql_injection(user_input: str) -> dict

Returns a severity classification (none/low/medium/high) in addition to the boolean.

dk.validate_input_against_sql_injection("' UNION ALL SELECT username, password FROM users--")
# {'suspicious': True, 'matched_patterns': 4, 'severity': 'high'}

check_security_headers(headers: dict) -> dict

dk.check_security_headers({"Content-Security-Policy": "default-src 'self'"})
# {'checklist': {...}, 'missing': [...], 'weak_configurations': [...], 'score': 33}

verify_csp_header(csp_header: str) -> dict

dk.verify_csp_header("default-src 'self'; script-src 'unsafe-inline'")
# {'issues': [...], 'safe': False}

6. Network-level defense

(Run these only against systems you own or are authorized to assess.)

check_tls_version_support(hostname, port=443, timeout=5.0) -> dict

dk.check_tls_version_support("example.com")
# {'tls_version': 'TLSv1.3', 'outdated': False, 'cipher_suite': '...', 'weak_cipher': False}

check_firewall_rules_status(rules: list[dict]) -> dict

dk.check_firewall_rules_status([{"source": "0.0.0.0/0", "port": 22}])
# {'total_rules': 1, 'risky_count': 1, ...}

detect_arp_spoofing(arp_table: dict, known_good_mappings: dict) -> list[dict]

dk.detect_arp_spoofing({"192.168.1.1": "AA:BB:CC:DD:EE:FF"}, {"192.168.1.1": "11:22:33:44:55:66"})

validate_dns_response(hostname, resolved_ip, expected_ips) -> dict

check_vpn_connection_security(public_ip_before, public_ip_after, dns_servers_after, expected_vpn_dns) -> dict

audit_server_config(config: dict) -> list[str]

dk.audit_server_config({"debug": True, "firewall_enabled": False})
# ['Debug mode is on - must not be enabled in production', 'Firewall is disabled']

7. Cryptography & secrets management

generate_secure_token(length_bytes=32) -> str

ApiKeyRecord / rotate_api_key(current, grace_period_seconds=3600) -> tuple

mask_sensitive_data_in_logs(log_line, fields_to_mask=(...)) -> str

dk.mask_sensitive_data_in_logs('login attempt password="hunter2" user=barman')
# 'login attempt password=***REDACTED*** user=barman'

encrypt_sensitive_data(plaintext, key: bytes) -> str / decrypt_sensitive_data(token, key: bytes) -> str

AES-256-GCM. Requires pip install "defendking[full]".

import secrets
key = secrets.token_bytes(32)
token = dk.encrypt_sensitive_data("top secret", key)
dk.decrypt_sensitive_data(token, key)   # 'top secret'

validate_jwt_token(token, secret, algorithms=None) -> dict

Also rejects alg: none tokens explicitly.

check_secrets_in_codebase(directory, file_extensions=(...)) -> list[dict]

Detects AWS/GitHub/Slack/Google/Stripe/SendGrid/Twilio/Mailgun keys, JWTs, private keys, and DB connection strings with embedded credentials.

dk.check_secrets_in_codebase("./src")
# [{'file': './src/config.py', 'line': 4, 'type': 'Possible GitHub personal access / OAuth token'}]

8. Monitoring, risk scoring & reporting

SecurityFinding(category, description, severity, timestamp=now)

severity must be one of low/medium/high/critical.

calculate_risk_score(findings: list[SecurityFinding]) -> dict

findings = [dk.SecurityFinding("auth", "weak password policy", "high")]
dk.calculate_risk_score(findings)
# {'score': 14, 'level': 'low', 'finding_count': 1, 'by_severity': {'high': 1}, 'has_critical_finding': False}

generate_security_report(findings, target_name="system") -> str

Markdown report.

export_findings_to_json(findings, output_path) -> dict

dk.export_findings_to_json(findings, "report.json")
# {'success': True, 'path': 'report.json'}

generate_incident_response_report(incident_title, detected_at, affected_systems, actions_taken) -> str

audit_user_permissions(users: list[dict], expected_max_role: dict) -> list[dict]

notify_admin_dashboard(finding, webhook_url) -> dict / send_security_alert(message, telegram_bot_token, chat_id) -> dict

schedule_periodic_scan(interval_seconds, scan_function, max_runs=None) -> None

generate_security_checklist(system_type) -> list[str]

system_type is one of web/server/network/cloud/mobile.

dk.generate_security_checklist("cloud")

9. API & session security

validate_api_request_signature(payload, timestamp, signature, secret, tolerance_seconds=300) -> dict

HMAC-SHA256 request signing/verification (the pattern used by most REST/exchange/trading APIs).

import time, hmac, hashlib
secret = "shared-secret"
ts = str(time.time())
sig = hmac.new(secret.encode(), f"{ts}{payload}".encode(), hashlib.sha256).hexdigest()
dk.validate_api_request_signature(payload, ts, sig, secret)
# {'valid': True, 'reason': None}

detect_replay_attack(nonce, seen_nonces: set, max_stored=100_000) -> bool

seen = set()
dk.detect_replay_attack("req-123", seen)   # False (new)
dk.detect_replay_attack("req-123", seen)   # True (replay!)

check_session_fixation(pre_login_session_id, post_login_session_id) -> dict

dk.check_session_fixation("sess-abc", "sess-abc")
# {'rotated': False, 'vulnerable_to_fixation': True, ...}

generate_scoped_api_key(scopes: list[str], prefix="sk") -> dict

dk.generate_scoped_api_key(["read", "trade"])
# {'api_key': 'sk_...', 'stored_hash': '...', 'scopes': ['read', 'trade'], ...}

check_api_rate_limit_headers(headers: dict) -> dict

dk.check_api_rate_limit_headers({"X-RateLimit-Remaining": "0", "Retry-After": "30"})
# {'should_back_off': True, 'suggested_backoff_seconds': 30, ...}

Known limitations

  • Heuristic detection still isn't a real classifier. detect_xss_patterns, validate_input_against_sql_injection, and check_suspicious_url are regex-based signals, not a guarantee of safety. A determined attacker can craft a payload that slips past a fixed pattern list. Always pair them with the real defenses: parameterized queries/ORM for SQL, contextual output encoding + a strict CSP for XSS, and a reputation/block-list service for URLs.
  • The local common-password list is a sample, not a real breach corpus. check_password_breached queries the Have I Been Pwned API by default — the local list is only an offline fallback.
  • detect_anomalous_login_location gives an accurate result only when you pass real previous_coords/new_coords (haversine distance via distance_km_between). Without coordinates it falls back to a conservative fixed-distance estimate.
  • detect_replay_attack's in-memory seen_nonces set doesn't expire entries by time, only by count (max_stored) — for a real multi-process service, back it with a TTL-based store (e.g. Redis).
  • schedule_periodic_scan is a simple blocking loop for scripts/demos, not a production scheduler — use APScheduler or a system cron job for real deployments.

Changelog

2.5.1

  • Added defendking.exceptions (DefendKingError, InvalidInputError, ExternalServiceError) and applied a consistent error-handling convention across every function (see Error handling).
  • Substantially deepened detection accuracy across every section: password entropy scoring, homoglyph/TLD-swap domain-similarity checks, weighted risk scoring for URLs and phishing emails, SQLi severity classification, more secret-scanning patterns, more security-header/CSP checks, "high confidence" flagging for impossible-travel detection, and more.
  • Full README rewrite with per-function documentation and examples.
  • No new functions were added in this release — the focus was entirely on robustness and detection depth of the existing ~65 functions plus the five functions the 1.5.0 API-security section already introduced.

1.5.0

  • New section: API & session security (validate_api_request_signature, detect_replay_attack, check_session_fixation, generate_scoped_api_key, check_api_rate_limit_headers).
  • First pass at sharpening detection across passwords, URLs/phishing, XSS/SQLi, file extensions, secret-scanning, security headers/CSP, and firewall/default-credential checks.

1.0.0

  • Initial public release: 8 sections, ~65 functions.

Versioning

Following semantic-ish convention: first digit = structural changes, second = new features, third = bug fixes.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

defendking-2.5.1.tar.gz (59.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

defendking-2.5.1-py3-none-any.whl (46.7 kB view details)

Uploaded Python 3

File details

Details for the file defendking-2.5.1.tar.gz.

File metadata

  • Download URL: defendking-2.5.1.tar.gz
  • Upload date:
  • Size: 59.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.8.10

File hashes

Hashes for defendking-2.5.1.tar.gz
Algorithm Hash digest
SHA256 01e1e4581d7da35ab8a2caddeab1b7ef30e3ddf64297e117a15a0328c0520470
MD5 d2bb0da2ba7538fb4b2bcff551fdd8e8
BLAKE2b-256 30af9f66ed643dc147da2d652fe9b924363894d01a99aa2f0c93075c3be4ec7a

See more details on using hashes here.

File details

Details for the file defendking-2.5.1-py3-none-any.whl.

File metadata

  • Download URL: defendking-2.5.1-py3-none-any.whl
  • Upload date:
  • Size: 46.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.8.10

File hashes

Hashes for defendking-2.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c350528de7d00792f4c62348cae394c0f19907d2a44a870b4027afc735158719
MD5 bded483a5f14af9f8e0b73d8831f4e62
BLAKE2b-256 8370875f24bac555145dba0a5266b680f6ae61b5b8d260f6faa6ed7c1188cd4c

See more details on using hashes here.

Release history Release notifications | RSS feed

3.6.17

2 files

3.6.16

2 files

This release

2.5.1 This release

2 files

1.5.0

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page