CVE Patch Review

GHSA-GGXF-37HM-9WQF: Root-cause Fix for Unsafe Challenge Path Parsing in instagrapi

GHSA-GGXF-37HM-9WQF · Updated 2026-05-23 Root-cause

Summary

The patch addresses a trust-boundary failure in instagrapi challenge handling where server-provided path fields were concatenated into authenticated request URLs without validation. The fix centralizes path validation, rejects absolute or malformed paths, and adds regression tests that confirm no outbound authenticated request or captcha solver invocation occurs for attacker-controlled external targets.

Analysis

Vulnerability

GHSA-GGXF-37HM-9WQF describes a session leakage issue in instagrapi before 2.6.9. The vulnerable code trusted challenge response fields such as api_path and navigation.forward and interpolated them directly into authenticated request URLs. The patch summary shows constructions like "https://i.instagram.com/api/v1%s" % data["api_path"] and "https://i.instagram.com%s" % api_path, which allowed malformed values to alter the effective destination of subsequent requests.

This is a classic URL construction bug at a trust boundary: data returned by the remote service was treated as a safe path segment, but values such as //attacker.example/steal or @attacker.example/steal can change URL interpretation in downstream HTTP handling. Because these requests are challenge-related and authenticated, the impact is credential or session material disclosure to an attacker-controlled host, matching the advisory summary. The issue and fix are documented in the upstream pull request PR #2516 and the advisory GHSA record.

"https://i.instagram.com/api/v1%s" % data["api_path"],
challenge_post_url = "https://i.instagram.com%s" % api_path
"https://i.instagram.com%s" % api_path,

Patch

The patch introduces a dedicated validator, _safe_challenge_api_path, and routes challenge URL creation through a new helper, _challenge_url. This is the key architectural improvement: instead of ad hoc string concatenation at each call site, all challenge-path handling now passes through a single validation routine.

The validator rejects inputs that are missing, non-string, empty, absolute, authority-like, backslash-containing, or control-character-bearing. Specifically, it uses urlsplit and rejects any value with a non-empty scheme or netloc, any path not starting with /, any path starting with //, any path containing \, and any path containing ASCII control characters. That directly addresses the reported external redirect/session leakage vector.

from urllib.parse import urlsplit

@staticmethod
def _safe_challenge_api_path(api_path: str, field_name: str = "api_path") -> str:
    if not isinstance(api_path, str) or not api_path:
        raise ClientError(f"Malformed challenge data from Instagram (missing {field_name}).")
    parts = urlsplit(api_path)
    has_control_chars = any(ord(char) < 32 or ord(char) == 127 for char in api_path)
    if (
        parts.scheme
        or parts.netloc
        or not api_path.startswith("/")
        or api_path.startswith("//")
        or "\\" in api_path
        or has_control_chars
    ):
        raise ClientError(f"Unsafe challenge path from Instagram: {field_name}")
    return api_path

def _challenge_url(self, api_path: str, prefix: str = "", field_name: str = "api_path") -> str:
    return f"https://i.instagram.com{prefix}{self._safe_challenge_api_path(api_path, field_name)}"

The call sites were updated to use this helper for both data.get("api_path") and nested fields like navigation.forward. The regression tests are well targeted: they verify that malformed external-looking paths raise ClientError and, critically, that private.get, private.post, and captcha_resolve are not invoked when validation fails. That confirms the fix blocks the dangerous side effect before any outbound authenticated request or solver interaction occurs. See the upstream patch.

Review

Pros

  • The fix addresses the root trust issue by validating untrusted challenge path fields before URL construction rather than trying to sanitize after the fact.
  • Validation is centralized in _safe_challenge_api_path, reducing the chance of inconsistent handling across challenge flows.
  • The checks are appropriately strict for a path-only field: no scheme, no netloc, must begin with a single slash, no backslashes, and no control characters.
  • The helper preserves intended behavior for legitimate relative API paths while preventing authority confusion and parser ambiguity.
  • Regression tests cover multiple entry points: generic challenge API, captcha flow, phone submission, and SMS captcha verification.
  • The tests assert absence of side effects, which is important because the vulnerability is about unintended authenticated egress, not just exception behavior.

Cons

  • The tests focus on representative malicious inputs such as @attacker.example/steal and //attacker.example/steal, but they do not visibly enumerate additional parser edge cases like encoded separators or unusual Unicode characters.
  • The patch is scoped to challenge-related URL construction shown in the diff; it does not by itself prove that similar URL concatenation patterns do not exist elsewhere in the codebase.
  • The validator allows any single-slash absolute path on the trusted host, which is correct for this bug, but it does not constrain paths to a narrower expected prefix set beyond the optional caller-supplied prefix.

Verdict

Root-cause.

This patch fixes the underlying vulnerability mechanism: untrusted challenge response fields were being used as URL components without structural validation. The new helper enforces path-only semantics before any request is built, and the regression tests demonstrate that malicious values are rejected before network or solver actions occur. Based on the provided diff and advisory, this is a technically sound and appropriately scoped remediation for GHSA-GGXF-37HM-9WQF, with upstream implementation details available in PR #2516.

Sources