Back to Intelligence

CVE-2026-75110: MemOS AI Agent Authentication Bypass (CVSS 9.8) — Detection and Remediation Guide

SA
Security Arsenal Team
August 17, 2026
12 min read

NVD has published CVE-2026-75110, a CVSS 9.8 (Critical) vulnerability in MemOS — the memory operating system used to give LLMs and AI agents persistent, queryable memory. The flaw is a textbook fail-open authentication bypass: in any deployment where AUTH_ENABLED=true is set but the undocumented, defaultless INTERNAL_SERVICE_SECRET environment variable is left unset, the internal-request check in src/memos/api/middleware/auth.py evaluates None == None and happily treats the caller as a trusted internal principal with scopes: ["all"].

The practical impact is severe: an unauthenticated, network-positioned attacker can interact with the MemOS API as a fully privileged internal service. For organizations using MemOS to store conversational history, user context, retrieved documents, or agent state, that means remote read/write access to the memory substrate of your AI agents — data exfiltration, memory poisoning, and downstream manipulation of agent behavior, all without credentials.

If you run MemOS in production, staging, or even an internet-reachable dev environment, treat this as an emergency change window item. The condition is silent — nothing in the logs or startup output warns you that the service is fail-open.


Technical Analysis

Affected Component

  • Product: MemOS (memory operating system for LLMs and AI agents)
  • Vulnerable code path: is_internal_request() in src/memos/api/middleware/auth.py
  • CVE: CVE-2026-75110
  • CVSS v3.1: 9.8 (Critical) — network vector, no privileges required, no user interaction

Root Cause: A Fail-Open None == None Comparison

The vulnerable logic is deceptively simple. The middleware determines whether a request originates from a trusted internal service by comparing an inbound HTTP header against an environment variable:

  1. os.getenv("INTERNAL_SERVICE_SECRET") is called to load the expected shared secret.
  2. The request's X-Internal-Service header value is read.
  3. The two values are compared for equality.

The failure mode emerges when INTERNAL_SERVICE_SECRET was never set — which is entirely possible because the variable is undocumented and has no default value. In that case:

  • os.getenv("INTERNAL_SERVICE_SECRET") returns None
  • An attacker simply omits the X-Internal-Service header, which also yields None
  • The comparison None == None evaluates to True

The request is then classified as an internal service call and granted the scope list ["all"] — effectively bypassing the entire authentication and authorization layer, even though the operator explicitly set AUTH_ENABLED=true and believes the API is protected.

Exploitation Requirements

  • Network reachability to the MemOS API listener (commonly served via uvicorn; frequently bound to 0.0.0.0 in container and docker-compose deployments)
  • AUTH_ENABLED=true configured
  • INTERNAL_SERVICE_SECRET unset (the vulnerable condition)
  • No authentication token, no header manipulation — just a plain request with the X-Internal-Service header absent

There is nothing to brute force and nothing to guess. This is a deterministic bypass of the most dangerous kind: it exploits a configuration absence, not a configuration mistake an operator would reasonably catch.

Exploitation Status

At time of writing, there is no confirmed in-the-wild exploitation and the CVE has not been added to CISA's Known Exploited Vulnerabilities (KEV) catalog. However, the vulnerability is fully described in the public NVD record, the exploit condition is trivial to test for (a single unauthenticated API call), and AI-agent infrastructure is an increasingly attractive target for data theft and prompt/memory poisoning. Defenders should assume scanning for exposed MemOS instances will begin quickly — the barrier to weaponization is effectively zero.


Detection & Response

The most reliable detection posture combines three angles: (1) identifying vulnerable configuration state before an attacker does, (2) detecting anomalous unauthenticated access to the MemOS API, and (3) hunting for post-exploitation behavior against the memory store.

Sigma Rules

The first rule targets the core exploitation signature at the web/proxy layer: requests hitting MemOS API paths with no X-Internal-Service header present, succeeding with 2xx responses — the tell-tale of the None == None bypass. The second targets reconnaissance and probing of AI-agent memory endpoints from non-internal sources. Tune URI prefixes to match your reverse-proxy routing for MemOS.

YAML
---
title: MemOS API Access Without Internal Service Header - Potential CVE-2026-75110 Exploitation
id: 3f8c2a41-9b7e-4d12-a6f5-cve202675110
status: experimental
description: Detects successful HTTP requests to MemOS API endpoints that omit the X-Internal-Service header. In deployments vulnerable to CVE-2026-75110 (AUTH_ENABLED=true with INTERNAL_SERVICE_SECRET unset), such requests fail open and are granted scopes ["all"].
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-75110
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.initial_access
  - attack.t1190
logsource:
  category: webserver
detection:
  selection_uri:
    cs-uri|contains:
      - '/product/'
      - '/memories'
      - '/add'
      - '/search'
      - '/chat'
  selection_status:
    sc-status:
      - 200
      - 201
  filter_header_present:
    cs-header|contains: 'X-Internal-Service'
  condition: selection_uri and selection_status and not filter_header_present
falsepositives:
  - Legitimate external API consumers if MemOS endpoints are intentionally exposed without internal-header auth (indicates a separate architectural risk)
  - Health check endpoints if routed under the same URI prefix
level: high
---
title: External Reconnaissance or Bulk Access Against MemOS Memory API
id: 8d4e6b17-2c5a-4f89-b1d3-a7e9f2c4b6d8
status: experimental
description: Detects high-volume or scripted interaction with MemOS memory search/read endpoints from a single source, consistent with post-bypass data exfiltration of agent memory stores via CVE-2026-75110.
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-75110
author: Security Arsenal
date: 2026/04/06
tags:
  - attack.collection
  - attack.t1530
logsource:
  category: webserver
detection:
  selection:
    cs-uri|contains:
      - '/search'
      - '/memories'
      - '/get_all'
      - '/dump'
      - '/export'
  timeframe: 5m
  condition: selection | count(c-ip) by cs-uri > 50
falsepositives:
  - Legitimate agent workloads performing heavy memory retrieval — baseline per-source rates before enabling at high severity
  - Load testing activity
level: medium

KQL (Microsoft Sentinel / Defender)

If you ingest MemOS host and reverse-proxy telemetry into Sentinel (via Syslog/CEF from your NGINX/Envoy ingress, or via a custom log table), this query surfaces external sources successfully hitting MemOS API routes without internal-service headers, and flags sources with broad endpoint coverage — the exfiltration pattern after a successful bypass.

KQL — Microsoft Sentinel / Defender
// Hunt: Successful unauthenticated access to MemOS API consistent with CVE-2026-75110
// Adjust MemOSEndpoints to your actual route prefixes and the port to your deployment (commonly 8000/uvicorn)
let MemOSPorts = dynamic([8000, 8080]);
CommonSecurityLog
| where TimeGenerated > ago(24h)
| where DestinationPort in (MemOSPorts) or RequestURL has_any ("/product/", "/memories", "/search", "/chat")
| where RequestURL has_any ("/product/", "/memories", "/add", "/search", "/chat", "/get_all")
| where AdditionalExtensions !has "X-Internal-Service" or isempty(AdditionalExtensions)
| where HttpStatusCode >= 200 and HttpStatusCode < 300
| summarize Requests = count(), DistinctEndpoints = dcount(RequestURL), Endpoints = make_set(RequestURL, 20), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationHostName
| where DistinctEndpoints > 3 or Requests > 100
| project FirstSeen, LastSeen, SourceIP, DestinationHostName, Requests, DistinctEndpoints, Endpoints
| order by Requests desc;

For environments forwarding application-layer logs via Syslog instead:

KQL — Microsoft Sentinel / Defender
// Syslog-ingested MemOS/uvicorn access logs: flag external IPs receiving 2xx on memory endpoints
Syslog
| where TimeGenerated > ago(24h)
| where SyslogMessage has_any ("/memories", "/product/", "/search", "/chat", "/add")
| where SyslogMessage has " 200 " or SyslogMessage has " 201 "
| extend SourceIP = extract(@'^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', 1, SyslogMessage)
| where isnotempty(SourceIP)
| where not (ipv4_is_private(SourceIP))
| summarize Hits = count(), Paths = make_set(SyslogMessage, 10) by SourceIP, bin(TimeGenerated, 1h)
| order by Hits desc;

Velociraptor VQL

The highest-value host-side hunt is configuration-state verification: find MemOS processes and confirm whether INTERNAL_SERVICE_SECRET is actually present in their environment, and whether the API is bound to a non-loopback interface. On Linux hosts, process environments are readable from /proc/<pid>/environ.

VQL — Velociraptor
-- Hunt: MemOS processes missing INTERNAL_SERVICE_SECRET with non-loopback listeners (CVE-2026-75110 exposure)
-- Step 1: enumerate MemOS API processes
SELECT Pid, Name, CommandLine, Username, CreateTime,
       read_file(filename=format(format='/proc/%v/environ', args=Pid), length=65536) AS ProcEnv
FROM pslist()
WHERE CommandLine =~ 'memos|uvicorn'
  AND CommandLine =~ 'api'
VQL — Velociraptor
-- Step 2: correlate with listening sockets bound to 0.0.0.0 / external interfaces
SELECT Pid, Name, CommandLine
FROM pslist()
WHERE CommandLine =~ 'memos'

SELECT Laddr, Lport, Raddr, Rport, Status, Pid, Name
FROM netstat()
WHERE Status =~ 'LISTEN'
  AND Laddr =~ '^(0\.0\.0\.0|::)$'
  AND Pid IN (SELECT Pid FROM pslist() WHERE CommandLine =~ 'memos|uvicorn')

Any MemOS/uvicorn PID whose /proc/<pid>/environ blob does not contain the string INTERNAL_SERVICE_SECRET= and that holds a 0.0.0.0 listener is a confirmed CVE-2026-75110-exposed instance — prioritize it for immediate remediation.

Verification & Hardening Script

Run this on every Linux host or container running MemOS. It checks for the vulnerable configuration state, tests the fail-open condition safely against the local listener, applies the fix, and re-verifies. Adjust MEMOS_PORT to your deployment.

Bash / Shell
#!/usr/bin/env bash
# CVE-2026-75110 - MemOS fail-open auth bypass: detect, remediate, verify
set -euo pipefail

MEMOS_HOST="127.0.0.1"
MEMOS_PORT="${MEMOS_PORT:-8000}"
ENV_FILE="${ENV_FILE:-/etc/memos/memos.env}"   # adjust to your deployment (docker-compose .env, systemd EnvironmentFile, etc.)

echo "[*] Step 1: Check whether INTERNAL_SERVICE_SECRET is set in the running environment"
VULN=0
for pid in $(pgrep -f 'memos|uvicorn' || true); do
  if tr '\0' '\n' < "/proc/${pid}/environ" 2>/dev/null | grep -q 'AUTH_ENABLED=true'; then
    if ! tr '\0' '\n' < "/proc/${pid}/environ" 2>/dev/null | grep -q '^INTERNAL_SERVICE_SECRET=.'; then
      echo "[!!] PID ${pid}: AUTH_ENABLED=true but INTERNAL_SERVICE_SECRET is UNSET -> VULNERABLE (CVE-2026-75110)"
      VULN=1
    else
      echo "[OK] PID ${pid}: INTERNAL_SERVICE_SECRET is set"
    fi
  fi
done

echo "[*] Step 2: Safe local probe — request WITHOUT X-Internal-Service header must be rejected (401/403)"
HTTP_CODE=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 5 "http://${MEMOS_HOST}:${MEMOS_PORT}/docs" || echo "000")
if [[ "${HTTP_CODE}" == "200" ]]; then
  echo "[!!] Unauthenticated request returned 200 — fail-open condition likely present"
  VULN=1
elif [[ "${HTTP_CODE}" == "401" || "${HTTP_CODE}" == "403" ]]; then
  echo "[OK] Unauthenticated request rejected with ${HTTP_CODE}"
else
  echo "[?] Probe returned ${HTTP_CODE} — verify endpoint path and auth middleware manually"
fi

if [[ "${VULN}" -eq 1 ]]; then
  echo "[*] Step 3: Generating strong INTERNAL_SERVICE_SECRET and writing to ${ENV_FILE}"
  SECRET=$(openssl rand -hex 32)
  touch "${ENV_FILE}" && chmod 600 "${ENV_FILE}"
  grep -v '^INTERNAL_SERVICE_SECRET=' "${ENV_FILE}" > "${ENV_FILE}.tmp" || true
  echo "INTERNAL_SERVICE_SECRET=${SECRET}" >> "${ENV_FILE}.tmp"
  mv "${ENV_FILE}.tmp" "${ENV_FILE}"
  echo "[OK] Secret written. RESTART the MemOS service for the change to take effect:"
  echo "     systemd:   systemctl restart memos"
  echo "     docker:    docker compose --env-file ${ENV_FILE} up -d --force-recreate"
  echo "[!!] IMPORTANT: distribute this same secret to every legitimate internal service caller"
  echo "     and have them send it as the X-Internal-Service header."
fi

echo "[*] Step 4: Post-restart verification (run again after restart)"
echo "    curl -sk -o /dev/null -w '%{http_code}' http://${MEMOS_HOST}:${MEMOS_PORT}/docs"
echo "    Expected: 401 or 403. If 200, escalate immediately."

echo "[*] Step 5: Network containment check — confirm the API is not bound to 0.0.0.0 unintentionally"
ss -ltnp 2>/dev/null | grep -E 'memos|uvicorn|python' | grep '0.0.0.0' \
  && echo "[!!] MemOS API is listening on all interfaces — restrict binding or firewall it" \
  || echo "[OK] No wildcard listener found for MemOS processes"

Remediation

Immediate Actions (Do Today)

  1. Set INTERNAL_SERVICE_SECRET on every MemOS instance. Generate a cryptographically random value (minimum 32 bytes, e.g. openssl rand -hex 32), inject it via your environment/secrets manager, and restart the service. The check is read at request time from process environment, but a restart guarantees clean state.
  2. Distribute the same secret to all legitimate internal callers and configure them to send it as the X-Internal-Service header. Failing to do this will break internal service-to-service traffic once the variable is set — coordinate the cutover.
  3. Verify the fix. An unauthenticated request with no X-Internal-Service header must now receive 401 or 403. A request with the correct header should succeed with internal scopes. Test both paths explicitly — do not assume.
  4. Reduce network exposure. MemOS is an internal memory substrate, not a public API. Bind the listener to loopback or an internal interface, place it behind an authenticated ingress or service mesh (mTLS), and add firewall/security-group rules restricting access to known agent orchestrators. If the instance was ever internet-reachable, treat it as potentially compromised.

Patch and Vendor Guidance

  • Upgrade MemOS to the latest release from the official project repository. Given that the root cause is a coding flaw (fail-open comparison against an unset, undocumented variable), the durable fix must come from the upstream project — expect the maintainers to (a) fail closed when INTERNAL_SERVICE_SECRET is unset with AUTH_ENABLED=true, and (b) refuse startup or emit a hard warning on the dangerous configuration. Monitor the NVD entry for CVE-2026-75110 and the project's GitHub security advisories for the patched version number, and pin to it in your dependency manifests.
  • Check CISA KEV regularly; this CVE is not listed at publication time, but trivially exploitable 9.8s on internet-adjacent AI infrastructure are prime candidates.

Compromise Assessment

If you confirm a vulnerable-and-exposed instance existed for any period:

  • Review access logs (uvicorn/ingress) for requests to memory endpoints from unrecognized source IPs, especially successful 2xx responses without the internal header.
  • Audit the memory store itself. An attacker with scopes: ["all"] could have written to memory — look for injected content, unexpected memory entries, or configuration changes. Memory poisoning is a persistence mechanism for AI agents: tainted memories influence future agent behavior long after the vulnerability is patched.
  • Rotate everything MemOS could touch: API keys stored in or retrievable via memory, downstream service credentials used by agents, and any user PII handling context that passed through the store.
  • Rebuild from a known-good memory snapshot if integrity cannot be established.

Longer-Term Hardening

  • Fail-closed as policy: For any internally developed middleware, treat "expected secret is unset" as a startup-fatal error, never a runtime comparison against None. Add this pattern — os.getenv(...) compared directly against a header value — to your code review and SAST checklists; it is a common and recurring Python anti-pattern in AI tooling.
  • Document your AI infrastructure attack surface. MemOS, vector stores, orchestration frameworks, and tool servers are increasingly internet-adjacent. Include them in external attack surface management and authenticated vulnerability scanning scope.
  • Baseline egress from AI agent hosts. An attacker reading memory at scale generates anomalous egress volume; netflow or proxy-based egress alerting on these hosts catches what request-level logging misses.

Conclusion

CVE-2026-75110 is a reminder that the AI stack inherits — and amplifies — classic web security failures. A missing environment variable turned a deliberately enabled authentication layer into an open door with full privileges. The detection content above will help you find exposed instances and catch exploitation attempts, but the decisive action is simple: set the secret, verify the rejection, constrain the network path, and audit the memory store for tampering. Do it before someone else's scanner finds your instance first.

Related Resources

Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.