CR: netapi Security Hardening — Implementation

Implementation

Phase 1: Dependency Patching

Updated pyproject.toml with explicit version floors for vulnerable packages:

dependencies = [
    "requests>=2.33.0",           # CVE fix
    "cryptography>=46.0.5",       # CVE fix
    "pyasn1>=0.6.3",              # CVE fix
    "python-socketio>=5.14.0",    # CVE fix
    # ... other deps
]

Phase 2: genie/pyats Removal

Problem: Cisco genie/pyats pins pyasn1⇐0.6.2 which conflicts with the security fix.

Solution: Removed genie/pyats from the parsing extra entirely.

# CLI output parsing
parsing = [
    "textfsm>=1.1",
    "ntc-templates>=6.0",
    "ttp>=0.9",
]

# NOTE: Cisco pyATS/Genie removed due to unfixed CVEs (pyasn1, socketio)
# If needed, install separately: pip install genie pyats

Phase 3: Unified Exception Hierarchy

Created netapi.primitives.exceptions with vendor-aware base classes:

class NetapiError(Exception):
    """Base exception for all netapi errors."""
    vendor: str = "netapi"

class NetapiApiError(NetapiError):
    """HTTP API returned error (4xx, 5xx)."""
    status_code: int | None

class NetapiAuthError(NetapiError):
    """Authentication failed."""

class NetapiConnectionError(NetapiError):
    """Network unreachable."""

class NetapiNotFoundError(NetapiError):
    """Resource not found (404)."""

class NetapiRateLimitError(NetapiError):
    """Rate limit exceeded."""

class NetapiTimeoutError(NetapiError):
    """Request timeout."""

Phase 4: Vendor Exception Migration

Migrated vendor-specific exceptions to inherit from NetapiError:

Vendor Status Notes

pfSense

Done

PfSenseError(NetapiError)

WLC

Done

WlcError(NetapiError), WlcSshError(NetapiError)

GitHub

Done

GitHubError(NetapiError)

GitLab

Done

GitLabError(NetapiError)

Gitea

Done

GiteaError(NetapiError)

ISE

Done

8 clients: ERS, MnT, OpenAPI, pxGrid, SAML, Certs, Backup, DataConnect

Synology

Done

SynologyError(NetapiError)

Infoblox

Done

InfobloxError(NetapiError)

Keycloak

Done

KeycloakError(NetapiError)

KVM

Done

KvmError(NetapiError)

FMC

Done

FmcError(NetapiError)

ASA

Done

AsaError(NetapiError)

IOS-XE

Done

IosXeError(NetapiError), IosSshError(NetapiError)

Vault

N/A

No custom exceptions

Wazuh

N/A

No custom exceptions

Cloudflare

N/A

No custom exceptions

Phase 5: Bare Except Cleanup

Fixed bare except: clauses that swallow all exceptions:

File Fix

pfsense/client.py

except:except (ValueError, JSONDecodeError) with logging

mnt_client.py

except:except (ValueError, JSONDecodeError) with proper error propagation