Sep 18, 2026·8 min read·19 visits
A non-blind SSRF in Obot Platform < 0.23.0 allows privileged users to query local network assets and extract cloud metadata credentials (such as AWS IAM tokens) via remote MCP registration.
An authenticated Server-Side Request Forgery (SSRF) vulnerability in the Obot Platform allows administrative or power users to bypass IP verification and scan or query internal resources, private networks, and cloud instance metadata services (IMDS). Because response bodies and error details are reflected back to the client interface, this constitutes a non-blind SSRF.
The Obot Platform is an open-source system designed for AI bot governance, orchestrating interactions between large language models and external computational services. A crucial functionality within Obot is the integration of remote Model Context Protocol (MCP) servers and remote MCP catalogs. These components allow the core Obot engine to dynamically load tool schemas, query local or remote resources, and facilitate complex agentic workflows.
To configure these remote integrations, users with privileged access roles (Power User, Power User Plus, or Admin) can define endpoints via the management interface. During registration, the application accepts a user-defined URL from which the Obot backend orchestrator fetches configuration data and OAuth discovery metadata. This mechanism exposes an attack surface centered on server-side outbound HTTP requests.
In versions of the Obot Platform prior to 0.23.0, the backend infrastructure did not perform sufficient network validation of user-defined remote MCP URLs. The application failed to restrict the host resolution process to public network ranges, allowing the backend background controller to make HTTP connections to loopback interfaces, private networks (RFC 1918), and cloud link-local addresses (RFC 3927).
This security flaw corresponds to CWE-918 (Server-Side Request Forgery) and CWE-1188 (Initialization of a Resource with an Insecure Default). Because Obot reflects connection failures, parsing errors, and response content back to the administration dashboard, this vulnerability functions as a non-blind SSRF. Attackers can leverage this state to enumerate local services and extract sensitive configuration or credential payloads.
The root cause of GHSA-jgh3-fggc-mcpm is the failure of the Obot server core to restrict destination IP addresses prior to and during outbound HTTP requests. When a privileged user registers a remote MCP URL, the input string is checked only for format compliance and protocol scheme (strictly enforcing http or https). No subsequent DNS resolution checks or IP filter steps are applied during the registration phase.
Once registered, background synchronization tasks run asynchronously to query the target server. These tasks attempt to pull necessary OAuth configurations and discovery metadata. The synchronization logic makes direct HTTP requests to the user-supplied endpoint without performing domain resolution verification. If an attacker provides an address that resolves to local host space or an internal system, the core platform executes the request from its own execution environment.
Furthermore, the initial configuration parameters of the application left loopback resolution checks disabled by default. The configuration flag designed to block local connections, DisallowLocalhostMCP, was set to false or ignored entirely within the automatic metadata-fetch code path. This default-insecure posture allowed arbitrary routing through internal resources.
Crucially, the server attempts to parse the fetched resource as a structured JSON object. When the response returned from the requested internal service is not a valid JSON configuration (for example, if it returns an HTML status page, plain text AWS credentials, or standard web server error output), the parser fails. The application then encapsulates the raw response body in the failure message and propagates it to the UI, allowing the attacker to read the internal data.
In vulnerable versions, the URL validation logic failed to account for hostname resolution variables, enabling attackers to pass endpoints that resolved to restricted local networks. In the patch merged under Commit 0d959d933ce23d02fc7b097109eb99aa4a743faf, the engineering team established a robust validator within pkg/mcp/loader.go to enforce access restrictions.
The following code segment demonstrates the patched validation method:
// ValidateRemoteMCPURL rejects remote MCP URLs that resolve to blocked local address ranges.
func ValidateRemoteMCPURL(ctx context.Context, rawURL string, config RemoteMCPURLValidationConfig) error {
if strings.TrimSpace(rawURL) == "" {
return nil
}
if config.AllowLocalhostMCP && config.AllowPrivateIPMCP && config.AllowLinkLocalMCP {
return nil
}
u, err := url.Parse(rawURL)
if err != nil {
return fmt.Errorf("failed to parse MCP server URL: %w", err)
}
hostname := strings.TrimSuffix(strings.ToLower(u.Hostname()), ".")
if !config.AllowLocalhostMCP && (hostname == "localhost" || strings.HasSuffix(hostname, ".localhost")) {
return fmt.Errorf("MCP server URL must not be a localhost URL: %s", rawURL)
}
// LookupHost handles literal IP addresses and hostnames consistently.
addrs, err := net.DefaultResolver.LookupHost(ctx, hostname)
if err != nil {
return fmt.Errorf("failed to resolve MCP server URL hostname: %w", err)
}
for _, addr := range addrs {
ip := net.ParseIP(addr)
if ip == nil {
continue
}
if !config.AllowLocalhostMCP && ip.IsLoopback() {
return fmt.Errorf("MCP server URL must not be a localhost URL: %s", rawURL)
}
if !config.AllowPrivateIPMCP && ip.IsPrivate() {
return fmt.Errorf("MCP server URL must not resolve to a private IP address: %s", rawURL)
}
if !config.AllowLinkLocalMCP && (ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast()) {
return fmt.Errorf("MCP server URL must not resolve to a link-local address: %s", rawURL)
}
}
return nil
}While the input validation function prevents the initial registration of restricted hostnames, it does not stop Time-of-Check to Time-of-Use (TOCTOU) exploits such as DNS Rebinding. An attacker could register a domain resolving to a public IP to pass the ValidateRemoteMCPURL check, and then update the DNS record to point to 127.0.0.1 before the background thread initiates the HTTP fetch.
To counter DNS rebinding, the patch introduces dial-time check controls. The application implements an outbound dialer configuration that intercept and validate resolved IP addresses at the socket-connection step immediately before connection negotiation. This ensures that the destination IP address is verified in real-time, completing the remediation of the vulnerability.
To exploit this vulnerability, an attacker must have administrative or power-user credentials on the target Obot deployment. Once authenticated, the attacker accesses the remote MCP server registration panel. The primary objective is to make the Obot server issue unauthorized HTTP requests to internal networks or local host endpoints and extract information from the returned responses.
A highly critical scenario occurs when the Obot instance is deployed within Amazon Web Services (AWS) or similar public cloud infrastructures. The attacker sets the target URL to point to the AWS Instance Metadata Service (IMDSv1) endpoint: http://169.254.169.254/latest/meta-data/iam/security-credentials/. This link-local IP handles identity verification requests from EC2 hosts.
Upon submitting the registration, the Obot backend initiates an asynchronous retrieval task. When the orchestrator receives the raw text response listing the server's IAM roles (e.g., obot-application-role), it fails to parse the plaintext list as a valid JSON object. This parsing failure triggers an error handler that outputs the exact string response to the UI error log. The attacker reads this role name directly from the screen.
The attacker updates the registered remote MCP URL to target the role endpoint directly: http://169.254.169.254/latest/meta-data/iam/security-credentials/obot-application-role. The background sync controller repeats the fetch, attempts to process the returned credentials payload, and generates another parsing error. The detailed error message returned in the UI exposes the raw AWS access keys, secret keys, and session tokens, allowing the attacker to assume the cloud identity.
The impact of GHSA-jgh3-fggc-mcpm is classified as High. The vulnerability allows complete compromise of confidential data accessible from the Obot host environment. Although the attacker must be authenticated and have administrative privileges to execute the attack, the potential scope of post-exploitation activities elevates the overall severity.
Because the SSRF is non-blind, the attacker can leverage the platform to conduct comprehensive internal network discovery. In containerized environments such as Kubernetes, the attacker can scan adjacent pods, query internal metrics endpoints, and identify unsecured databases or microservices. Outbound HTTP requests can interact with REST APIs, allowing the attacker to modify configurations, delete data, or execute state-changing actions.
The CVSS v3.1 vector is rated at 7.6 (High): CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:N. The Scope parameter (S) is defined as Changed (S:C) because the vulnerable application can be manipulated to interact with and extract resources outside its own security authority, notably cloud metadata infrastructure. Confidentiality (C) is rated as High (C:H) due to the direct leakage of IAM credentials and system information.
If the deployment uses managed service roles with elevated privileges, the extraction of AWS IAM credentials, GCP access tokens, or Azure Instance Metadata tokens could result in complete account takeover. The attacker could pivot from the compromised cloud metadata service to other corporate cloud assets, bypassing standard network perimeter controls.
Remediation of the vulnerability requires upgrading the Obot installation to version 0.23.0 or later. This release updates the default security posture by blocking loopback, private networks, and link-local ranges by default across all remote connections.
If the deployment requires connections to local or private services, administrators can explicitly permit specific ranges by configuring these environment variables. Disabling these blocks should be avoided unless robust network security layers are present:
OBOT_SERVER_DISALLOW_LOCALHOST_MCP=falseOBOT_SERVER_DISALLOW_PRIVATE_IP_MCP=falseOBOT_SERVER_DISALLOW_LINK_LOCAL_MCP=falseSecurity teams can identify exploitation attempts by auditing the application server logs. Look for specific error messages generated by the ValidateRemoteMCPURL function, such as:
"MCP server URL must not be a localhost URL""MCP server URL must not resolve to a private IP address""MCP server URL must not resolve to a link-local address"Additionally, implement network-level egress auditing. Configure egress firewalls, AWS Security Groups, or Kubernetes NetworkPolicies to prevent Obot container pods from communicating with the metadata IP address 169.254.169.254 and unauthorized internal subnets.
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Obot Platform Acorn Labs | < 0.23.0 | 0.23.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918, CWE-1188 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 7.6 (High) |
| Impact | Confidentiality High, Integrity Low, Availability None |
| Exploit Status | Proof-of-Concept / Conceptual |
| KEV Status | Not Listed |
The web application server-side code attempts to process a user-controlled URL without restricting the target IP address or hostname.
CVE-2026-118777 is a prototype pollution vulnerability (CWE-1321) in the Forge JavaScript cryptography and networking library (distributed on npm as node-forge) prior to version 1.4.1. The flaw resides in the forge.http client subsystem, where incoming HTTP cookie names and paths parsed from Set-Cookie response headers are stored directly into standard JavaScript objects without key validation or property isolation. By returning crafted Set-Cookie headers containing keys such as __proto__ or constructor, a malicious HTTP server can inject arbitrary properties into Object.prototype, attach attributes to the global Object constructor, or delete built-in prototype methods to cause an application-wide denial of service.
CVE-2026-118775 (GHSA-4642-5mcj-2rqw) is an integer overflow and validation flaw in the ASN.1 serialization module of Forge (node-forge) prior to version 1.4.1. The asn1.oidToDer() function fails to validate the range of the first two arcs of an Object Identifier (OID) and truncates the packed initial subidentifier to a single 8-bit integer. Applications that perform policy checks on untrusted OID strings before encoding them into Distinguished Encoding Rules (DER) format can be tricked into emitting DER bytes that correspond to a completely different, restricted OID.
CVE-2026-119194 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting versions 0.3.3 through 0.6.4. The flaw resides in the schemaless decoding routine ConstructedPayloadDecoderBase._decodeComponentsSchemaless used across BER, CER, and DER codecs. By sending an ASN.1 container populated with child components whose tag identifiers are separated by multiples of CPython's integer hash modulus (sys.hash_info.modulus), an unauthenticated attacker can force worst-case hash collisions in an unbounded Python set, degrading decoding performance from O(N) to O(N^2) and causing a Denial of Service (DoS).
CVE-2026-119195 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting all versions prior to 0.6.5. When decoding constructed strings or indefinite-length ANY types across BER, CER, and certain DER code paths, the payload decoders repeatedly concatenate incoming fragments onto an immutable bytes object using the += operator. Because Python bytes objects cannot be resized in-place, each fragment iteration allocates a new buffer and copies all previously accumulated bytes, resulting in quadratic O(N^2) time and memory copy complexity. An unauthenticated remote attacker can supply a highly fragmented ASN.1 stream to exhaust CPU cycles and stall application worker threads.
An algorithmic complexity vulnerability (CWE-407) in pyasn1 versions prior to 0.6.5 allows unauthenticated attackers to cause a Denial of Service (DoS) via crafted ASN.1 payloads. The flaw resides in the binary-encoded ASN.1 REAL mantissa deserialization routine within RealPayloadDecoder.valueDecoder. By performing iterative byte-string slicing and repeated bitwise shifts on a growing arbitrary-precision integer, the decoder exhibits quadratic time and memory allocation complexity relative to the mantissa length. Supplying a BER-, CER-, or DER-encoded payload with a large REAL mantissa causes excessive CPU consumption and blocks application worker processes.
A vulnerability classified under CWE-407 (Inefficient Algorithmic Complexity) exists in the pyasn1 library prior to version 0.6.5. When parsing constructed ASN.1 BIT STRING payloads under BER, CER, or schema-driven DER encoding rules, the BitStringPayloadDecoder repeatedly shifts and copies the entire accumulated bit value for each incoming fragment. Processing inputs with a large number of small constructed fragments induces quadratic CPU consumption, allowing unauthenticated remote attackers to cause a denial of service via resource exhaustion during the initial decoding phase.